개념 문제


개념 연습 문제는 특정 (프로그래밍) 개념을 가르치기 위해 설계된 연습 문제예요. 개념 연습 문제가 가르치는 개념들은 _실러버스_를 이뤄요. 실러버스를 설계하는 방법에 대한 더 자세한 내용은 실러버스 문서를 확인해 봐요.

Note

트랙의 루트 디렉터리에서 다음 명령을 실행하면 새 개념 연습 문제의 뼈대를 빠르게 만들 수 있어요:

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

더 자세한 내용은 configlet create 문서를 확인해 봐요

메타데이터

개념 연습 문제의 메타데이터는 config.json 파일의 exercises.concept 키에 정의돼요. 이 메타데이터는 연습 문제의 UUID, slug 등을 정의해요.

예시

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

파일

각 개념 연습 문제는 트랙의 exercises/concept 디렉터리 안에 자신만의 디렉터리를 가져요. 개념 연습 문제 디렉터리의 이름은 config.json 파일에 정의된 대로 개념 연습 문제의 slug 속성과 일치해야 해요.

개념 연습 문제에는 네 가지 종류의 파일이 있어요:

문서 파일

이 파일들은 연습 문제를 설명하는 데 도움을 주기 위해 학생에게 제공돼요.

  • .docs/introduction.md: 연습 문제가 학생에게 가르치는 개념을 소개해요 (필수)
  • .docs/instructions.md: 연습 문제에 대한 지침을 제공해요 (필수)
  • .docs/hints.md: 학생이 연습 문제에서 막혔을 때 스스로 벗어날 수 있도록 힌트를 제공해요 (필수)

메타데이터 파일

이 파일들은 학생에게 제공되지 않고, 연습 문제의 메타데이터를 정의하는 데 사용돼요.

  • .meta/config.json: 연습 문제에 대한 메타 정보를 담고 있어요 (필수)
  • .meta/design.md: 연습 문제의 설계를 설명해요 (필수)

접근법 파일

이 파일들은 연습 문제에 대한 접근법을 설명해요.

  • .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
└── 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 (exemplar implementation)
        ├── CarsAssemble.cs (stub implementation)
        └── CarsAssemblyTests.cs (tests)

최소 유효 사양

우리는 새 연습 문제에 "낙관적 병합" 접근법을 선호해요. 트랙은 연습 문제를 "작업 중" 상태로 개발할 수 있어요. configlet을 통과하고 병합할 수 있게 해 주는 최소 유효 상태는 다음과 같아요:

  • 트랙 config.json에 유효한 항목이 있고, status가 wip로 설정돼 있어요.
  • 유효한 .meta/config.json 파일이 있어요
  • 다음 파일들이 존재해요. 비어 있어도 괜찮아요:
    • .docs/introduction.md
    • .docs/instructions.md
    • .docs/hints.md
    • 스텁 구현
    • 테스트 파일

파일: .docs/introduction.md

목적: 연습 문제가 학생에게 가르치는 개념을 소개해요.

포함 여부: 필수

  • 제공하는 정보는 학생이 스스로 풀이를 알아낼 수 있을 만큼만 맥락을 제공해야 해요.
  • 개념의 기본을 이해하고 연습 문제를 풀기 위해 필요한 정보만 제공해야 해요. 추가 정보는 개념의 about.md 문서에 남겨 둬요.
  • 링크는 되도록 아껴 써요. 재귀처럼 복잡한 주제를 설명하는 링크는 유용할 수 있지만, 대부분의 개념에서는 링크가 필요한 것보다 많은 정보를 제공하니, 핵심을 간결하게 본문 안에서 설명하는 것을 목표로 해요.
  • 학생이 더 많은 정보를 쉽게 검색할 수 있도록 적절한 기술 용어를 사용해야 해요.
  • 코드 예시는 새로운 문법을 소개할 때만 사용해야 해요 (학생이 문법 예시를 찾느라 웹을 검색할 필요가 없어야 해요). 그 외의 경우에는 코드 대신 설명이나 링크를 제공해요.

예를 들어, "strings" 연습 문제의 소개에서는 문자열을 그저 "유니코드 문자의 나열" 또는 "바이트의 연속"이라고 설명하고, 사용자에게 문자열을 만드는 방법을 알려 주고, 문자열을 조작하는 데 쓸 수 있는 메서드가 있다고 설명할 수 있어요. 학생이 연습 문제를 풀기 위해 더 미묘한 세부 사항까지 이해할 필요가 없다면, 이런 짧은 설명(문법 예시와 함께)만으로도 학생이 연습 문제를 풀기에 충분해요.

예시

# 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
```

파일: .docs/introduction.md.tpl

목적: introduction.md 파일을 생성하는 데 사용하는 템플릿이에요.

포함 여부: 선택

introduction.md 문서는 연습 문제의 개념을 학생에게 소개해요. 각 개념에는 자신만의 introduction.md 문서도 있는데, 이는 연습 문제 맥락 밖에서는 표시되지 않아요.

개념의 소개를 연습 문제의 소개에 그대로 포함해야 한다면, introduction.md.tpl 파일을 사용할 수 있어요. 이 파일에서는 자리 표시자 %{concept:<concept-slug>}를 통해 개념 소개를 참조할 수 있어요.

configlet은 템플릿 파일로부터 introduction.md 파일을 생성할 수 있어요. 생성된 파일에서는 개념 자리 표시자가 해당 개념의 introduction 내용으로 바뀌어요.

Exercism 웹사이트는 introduction.md 문서만 알고 있어요. 템플릿 파일을 사용할 때 introduction.md를 생성하는 것은 트랙의 책임이에요.

트랙은 연습 문제마다 템플릿을 사용할지 여부를 결정할 수 있어요. 경우에 따라서는 개념의 소개를 그대로 쓰는 것이 최선이 아닐 수도 있어요. 항상 학생에게 가장 좋은 학습 경험을 제공하는 쪽을 선택해요.

예시

# Introduction

%{concept:variables}

파일: .docs/instructions.md

목적: 연습 문제에 대한 지침을 제공해요.

포함 여부: 필수

이 파일은 두 부분으로 나뉘어요.

  1. 첫 번째 부분은 연습 문제의 "이야기"나 "테마"를 설명해요. 일반적으로 코드 예시를 포함하지 않아요.
  2. 두 번째 부분은 학생이 해야 할 일을 하나 이상의 과제 형태로 명확하게 지침으로 제공해요.

각 과제는 다음 기준을 따라야 해요:

  • 숫자로 시작하는 2단계 제목으로 시작해요 (예: ## 1. Do X, ## 2. Do Y).
  • 제목은 무엇을 구현할지 설명해야 하고, 어떻게 구현할지는 설명하지 않아요 (예: ## 1. Check if an appointment has already passed).
  • 학생이 정의/구현해야 하는 함수나 메서드를 설명해요 (예: Implement method X(...) that takes an A and returns a Z),
  • 그 함수의 사용 예시를 코드로 제공해요. 이 예시는 테스트에 나온 것과 달라야 해요.

우리는 Exercism의 콘텐츠를 모든 사람에게 안전하게 만드는 것을 매우 중요하게 생각해요. 그래서 이야기가 적절한지 판단할 때는 신중한 쪽을 택해요. 병합할 내용을 검토할 때도 조심하지만, 무엇이 문제로 보일지는 알아채기 어렵다는 점을 잘 알고 있어요. 그래서 항상 여러분이 선의로 행동한다고 믿고, 검토 과정에서 문제를 비난하지 않는 방식으로 찾아내려고 노력해요. 이야기를 우리와 함께 점검하고 싶다면 @exercism/leadership을 멘션해 주세요. 함께 살펴볼게요. 몇 가지 지침은 다음과 같아요:

  • 이야기가 모두를 반갑게 맞이하고 누구나 이해할 수 있도록 해 봐요. 이야기에 내부 농담이나 지역 방언이 들어 있다면 다른 표현을 생각해 봐요.
  • 모든 사람을 포용하는 예시를 쓰도록 해 봐요. 예를 들어, 다른 문화의 이름과 다양한 성별을 사용하는 것을 고려해 봐요.
  • 이야기 때문에 기분이 상할 만한 사람을 직접 아는지 스스로 물어봐요. 그런 경우라면 피할 수 있도록 이야기를 바꾸는 것을 고려해 봐요.

예시

# 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
```

파일: .docs/hints.md

목적: 학생이 연습 문제에서 막혔을 때 스스로 벗어날 수 있도록 힌트를 제공해요.

포함 여부: 필수

  • 학생이 막히면 힌트를 요청하는 버튼을 클릭할 수 있고, 그러면 파일의 관련 부분이 표시돼요.
  • 힌트는 제목 아래에 글머리 기호로 나열해요.
  • 힌트는 거의 모든 학생의 막힘을 풀어 줄 만큼 충분해야 해요.
  • 힌트는 풀이를 그대로 알려 주지 않고, 풀이를 설명하는 자료를 가리켜야 해요 (예: 사용할 함수의 문서를 링크하기).
  • 힌트는 개념을 설명하기 위해 코드 예시를 사용할 수 있지만, 풀이의 개요를 제시하는 데는 쓰지 않아요. 예를 들어 배열 연습 문제에서는 특정 배열 함수가 어떻게 동작하는지 스니펫을 보여 줄 수 있지만, 풀이에 바로 복사해 붙여넣을 수 있는 방식은 아니에요.
  • 연습 문제에 대한 일반적인 힌트는 ## General 제목 아래에 Markdown 목록으로 나타낼 수 있어요.
  • 과제별 힌트는 instructions.md의 해당 과제 제목과 일치하는 제목 아래에 Markdown 목록으로 나타내야 해요 (예: ## 2. Do Y).
  • General 힌트가 없거나 특정 과제에 대한 힌트가 없으면 해당 제목은 생략해요. 모든 제목 뒤에는 Markdown 목록이 와야 해요.
  • 과제별 힌트가 일반 힌트보다 학생의 막힘을 풀 가능성이 높으니, 일반 힌트보다 과제별 힌트를 우선해요.
  • 과제 제목은 과제의 _무엇_을 설명해야 하고, _어떻게_를 설명해서는 안 돼요.
  • 과제 제목은 일반적인 문장 대소문자 규칙을 사용해요 (예: ## 2. Check if a book can be borrowed).
  • 과제는 어떤 메서드/함수/타입을 구현해야 하는지와 그 기댓값을 명확히 밝혀야 해요 (예: 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`).

힌트를 보는 것은 "권장" 경로가 아니며, 학생이 힌트 없이는 진행할 수 없을 때를 제외하면 (부드럽게) 사용을 말려요. 그러니 힌트를 읽는 학생은 다소 혼란스럽거나 압도당하고, 어쩌면 답답함을 느낄 수 있다는 점을 염두에 두면 좋아요.

예시

# 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

파일: .meta/design.md

목적: 연습 문제의 설계를 설명해요.

포함 여부: 필수

이 파일은 연습 문제의 설계에 대한 정보를 담고 있어요. 여기에는 목표, 교육 목표, 가르치지 말아야 할 것 등이 포함돼요. 이 정보는 연습 문제에 해당하는 GitHub 이슈에서 가져올 수 있어요.

이 파일은 향후 메인테이너나 기여자에게 연습 문제의 범위와 한계를 알려 주기 위해 존재해요. 시간이 지나면서 연습 문제가 점점 복잡해지는 자연스러운 흐름을 피하기 위해서예요.

예시

# 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.

파일: .meta/config.json

목적: 연습 문제에 대한 메타 정보를 담고 있어요.

포함 여부: 필수

이 파일은 연습 문제에 대한 메타 정보를 담고 있어요:

  • authors: 연습 문제 작성자의 GitHub 사용자 이름이에요 (필수)
    • 리뷰가 연습 문제를 실질적으로 바꿨다면(함께 완성했다고 느껴질 정도라면) 리뷰어도 포함해요
  • contributors: 연습 문제 기여자의 GitHub 사용자 이름이에요 (선택)
    • 리뷰가 의미 있거나 실행 가능하거나 실행에 옮겨졌다면 리뷰어도 포함해요.
  • forked_from: 어느 연습 문제에서 포크했는지예요 (연습 문제를 포크한 경우 필수)
  • files: 이 연습 문제에서 사용하는 파일의 위치예요. 연습 문제 디렉터리를 기준으로 한 상대 경로예요 (필수)
    • solution: 스텁 구현 파일이에요 (필수)
    • test: 테스트 파일이에요 (필수)
    • exemplar: 모범 구현 파일이에요 (필수)
    • editor: 편집기에서 읽기 전용으로 표시되는 다른 파일이에요 (선택)
    • invalidator: 변경되면 풀이가 최신 상태가 아니게 되는 파일이에요 (선택)
  • language_versions: 언어 버전 요구 사항이에요 (선택)
  • blurb: 이 연습 문제에 대한 짧은 설명이에요. 길이는 350 이하여야 해요. Markdown은 지원되지 않아요 (필수)
  • source: 이 연습 문제가 기반으로 한 출처예요 (선택)
  • source_url: 이 연습 문제가 기반으로 한 출처의 URL이에요 (선택)
  • representer: representer가 이 파일을 처리하는 방식과 관련된 메타 정보예요 (선택)
    • version: 연습 문제에 사용할 representer 버전을 나타내는 정수예요 (상위 키가 있으면 필수)
  • icon: 아이콘의 slug예요 (전체 아이콘 목록을 참고해요). 지정하지 않으면 연습 문제의 slug가 사용돼요 (선택)
  • custom: 연습 문제별 비표준 데이터예요. 연습 문제마다 트랙 도구의 동작을 사용자 정의하는 데 쓸 수 있어요 (선택)

어떤 사람이 작성자이_면서_ 기여자라면, 작성자로만 표시해요.

최소 예시

{
  "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"
}

전체 예시

사용자 FSharpForever가 F# 트랙을 위해 log-levels라는 연습 문제를 작성했다고 가정해요. PythonProfessor가 이 연습 문제를 Python 트랙에 맞게 각색해요. 나중에 사용자 GladToHelp가 연습 문제를 개선해요.

{
  "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
  }
}

다음 사항에 유의해요:

  • 작성자와 기여자의 순서는 중요하지 않고 아무 의미도 없어요.
  • 연습 문제를 포크하는 경우에는 원래 작성자나 기여자를 참조하지 않아요. forked_from이 올바른지만 확인해요.
  • 흔하지는 않지만, 여러 연습 문제에서 포크하는 것도 가능해요.
  • language_versions는 자유 형식 문자열이며, 트랙에서 자유롭게 사용하고 해석할 수 있어요.

파일: .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: 접근법의 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: 아티클을 고유하게 식별하는 V4 UUID예요. 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 |         - |

파일: 스텁 구현

목적: 학생에게 시작점을 제공해요.

포함 여부: 필수

  • 학생이 어디에 코드를 추가해야 할지 알 수 있도록 스텁을 설계해요.
  • 연습 문제에서 소개하지 않은 문법에 대해서는 스텁을 정의해요. 대부분의 연습 문제에서는 스텁 함수/메서드를 정의하는 것을 뜻해요.
  • 컴파일 언어라면 컴파일 가능한 코드를 두는 것을 고려해 봐요. 언어가 처음인 학생에게는 컴파일러 메시지가 이해하기 어려울 때가 있으니까요.
  • 코드는 가능한 한 단순해야 해요.
  • 연습 문제나 그 선수 개념에서 소개한 언어 기능만 사용해요 (그 선수 개념의 선수 개념까지도 마찬가지예요).
  • 스텁 파일은 브라우저에서 코딩할 때 학생에게 표시되고, CLI를 사용할 때는 학생의 파일 시스템으로 다운로드돼요.
  • 스텁 구현 파일의 상대 경로는 .meta/config.json 파일의 "files.solution" 키에 지정해야 해요.

예시

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

파일: 테스트

목적: 풀이의 정확성을 검증해요.

포함 여부: 필수

  • 테스트는 instructions.md 파일의 예시를 사용해서는 안 돼요.
  • 코드는 가능한 한 단순해야 해요.
  • 연습 문제의 선수 개념에서 소개한 언어 기능만 사용해요 (그 선수 개념의 선수 개념까지도 마찬가지예요).
  • 테스트 파일은 브라우저에서 코딩할 때 학생에게 표시되지 않지만, CLI를 사용할 때는 학생의 파일 시스템으로 다운로드_돼요_.
  • 테스트 파일의 상대 경로는 .meta/config.json 파일의 "files.test" 키에 지정해야 해요.

예시

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

파일: 모범 구현

목적: 학생이 목표로 삼아야 할 구현을 제공해요.

포함 여부: 필수

  • 이 구현은 학생이 목표로 삼기를 바라는 코드예요.
  • 멘토는 피드백을 작성할 때 이 코드를 "목표"로 표시받아요
  • 구현은 연습 문제나 그 선수 개념에서 소개한 언어 기능만 사용해야 해요 (그 선수 개념의 선수 개념까지도 마찬가지예요).
  • 모범 파일은 브라우저에서 코딩할 때 학생에게 표시되지 않고, CLI를 사용할 때도 학생의 파일 시스템으로 다운로드되지 않아요.
  • 모범 파일은 멘토가 풀이나 표현에 대해 논평할 때 표시돼요.
  • 모범 구현 파일의 상대 경로는 .meta/config.json 파일의 "files.exemplar" 키에 지정해야 해요.

예시

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

파일: 추가 파일

목적: 테스트를 실행할 수 있도록 보장해요.

포함 여부: 기본 파일만으로는 테스트를 실행할 수 없을 때 필수

일부 언어는 테스트를 실행하기 위해 추가 파일이 필요해요. 예를 들어 C#의 프로젝트 파일이나 Node의 package.json 파일이 없으면 테스트를 실행할 수 없어요.

공유 파일

일부 파일은 개별 연습 문제에 특정되지 않고 모든 연습 문제에 적용돼요. 더 자세한 내용은 문서를 확인해 봐요.

이름 짓기

개념 연습 문제의 이름은 그 개념이 아니라 이야기/테마를 따라 지어야 해요.

좋은 이름 예시:

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

허용되지 않는 이름:

  • Booleans: 이야기 이름이 아니라 개념 이름을 사용했어요
  • Exercise #1: 연습 문제는 이야기/테마가 아니에요

큰 변경 없이 연습 문제를 포크할 때는 가능하면 원래 이름을 사용해요.

Slug

각 연습 문제에는 _slug_도 있어요. slug는 다음 규칙에 따라 연습 문제 이름을 정규화한 버전이에요:

  1. 소문자를 사용해요.
  2. kebab-case를 사용해요.
  3. 라틴 영숫자와 대시를 사용해요 (정규식: [a-z0-9-]+)
  4. 특별히 숫자를 선호할 이유가 없다면 숫자 기호보다 철자로 쓴 숫자를 선호해요 (예: 2-fer보다 two-fer)

좋은 slug 예시:

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

허용되지 않는 slug:

  • TIM-FROM-MARKETING: 소문자를 사용하지 않았어요 (즉, tim-from-marketing)
  • TimFromMarketing: kebab-case를 사용하지 않았어요 (즉, tim-from-marketing)
  • floating-point-numbers: 이야기 이름이 아니라 개념 이름을 사용했어요

표시 방식

브라우저 편집기를 사용할 때와 CLI를 사용할 때 연습 문제 문서가 학생에게 표시되는 방식에는 차이가 있어요. 더 자세한 내용은 이 문서를 봐요.

아이콘

각 연습 문제에는 함께 제공되는 아이콘이 있어요. 기본적으로 표시되는 아이콘은 이름이 연습 문제의 slug와 일치하는 아이콘이에요. 연습 문제의 .meta/config.json 파일에 icon 속성을 지정하면 이를 바꿀 수 있어요.

기존 연습 문제를 포크하는 경우라면 그 연습 문제에 맞는 아이콘이 이미 있을 거예요. 없다면 website-icons 저장소에 이슈를 열어 주세요.