Skip to content

Commit

Permalink
Add syllabus docs (#369)
Browse files Browse the repository at this point in the history
Draft introduction to syllabus design.

I'm trying to give enough background for people to be able to
think about syllabus design in a way that is useful and not
too overwhelming.

Co-authored-by: Erik Schierboom <erik_schierboom@hotmail.com>
Co-authored-by: ee7 <45465154+ee7@users.noreply.github.com>
Co-authored-by: Jeremy Walker <jez.walker@gmail.com>
  • Loading branch information
3 people authored Sep 19, 2022
1 parent 149ec42 commit ba3eba3
Show file tree
Hide file tree
Showing 7 changed files with 291 additions and 0 deletions.
28 changes: 28 additions & 0 deletions building/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,34 @@
"title": "Concept Exercises",
"blurb": ""
},
{
"uuid": "038e26ee-891f-4592-92bd-c54cbd58d8bd",
"slug": "tracks/syllabus",
"path": "building/tracks/syllabus/README.md",
"title": "Syllabus",
"blurb": ""
},
{
"uuid": "af70ff3e-d4a4-4968-bcfe-1f197dc43380",
"slug": "tracks/syllabus/first-exercise",
"path": "building/tracks/syllabus/first-exercise.md",
"title": "First Exercise",
"blurb": ""
},
{
"uuid": "6f8d7376-70db-4f25-928c-4778bdf8a686",
"slug": "tracks/syllabus/next-exercises",
"path": "building/tracks/syllabus/next-exercises.md",
"title": "Next Exercises",
"blurb": ""
},
{
"uuid": "cb430e09-7710-43b8-ab0e-2f0ee3785cf9",
"slug": "tracks/syllabus/expanding",
"path": "building/tracks/syllabus/expanding.md",
"title": "Expanding",
"blurb": ""
},
{
"uuid": "ed318b17-01be-4868-92df-50a644adfdc7",
"slug": "tracks/concepts",
Expand Down
3 changes: 3 additions & 0 deletions building/tracks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ The track's configuration and metadata are specified in the `config.json` file.

All concept and practices exercises of a track involve _concepts_. These concepts are separate entities by themselves. Check the [documentation](/docs/building/tracks/concepts) for more information.

The concepts taught in the track's concept exercises form a _syllabus_.
For more information on how to design a syllabus, check the [syllabus documentation](/docs/building/tracks/syllabus).

## Exercises

Tracks have two types of exercises:
Expand Down
2 changes: 2 additions & 0 deletions building/tracks/concept-exercises.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Concept Exercises

[Concept Exercises](/docs/building/product/concept-exercises) are exercises designed to teach specific (programming) concepts.
The concepts taught by the concept exercises form a _syllabus_.
For more information on how to design a syllabus, check the [syllabus documentation](/docs/building/tracks/syllabus).

## Metadata

Expand Down
178 changes: 178 additions & 0 deletions building/tracks/syllabus/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
# Syllabus

A fully featured Exercism track has two types of exercises: Concept Exercises and Practice Exercises.
They are fundamentally different and complement each other well.

A track's [Concept Exercises](/docs/building/tracks/concept-exercises) are exercises designed to teach individual concepts that form the basis of a specific programming language.
These concepts form a _syllabus_.

This documentation contains pointers and tips on how to successfully design a syllabus for your track.

## The goal of a syllabus

The end goal of a syllabus is to lead students to be comfortable reading and writing idiomatic code in the target language.

Each individual Concept Exercise is very tightly focused.
It is a small and highly-targeted step that moves the student towards understanding something about the language.
It builds only on concepts that have been introduced previously.

By solving the exercise, the student begins the process of becoming familiar with the concept.
Understanding comes primarily through doing, much less so through explanations.
The explanatory content is there to **introduce** the student to the ideas they need to solve the exercise (thus the choice of filename- "introduction.md")

We want to allow students to start writing code immediately, without having to understand everything up front.
In order to achieve this we hand-wave over details and we leave a lot of things unexplained.
We simplify and provide code stubs where possible.
This reduces the cognitive burden of getting started and provides the time and space for the knowledge to sink in.
By taking this approach we're not saying that the student doesn't need to know these things, we're saying that they don't need to know them **yet**.

Often the earliest exercises need to contain non-idiomatic code.
This is because in the beginning most of the language is still unknown to the student, and most of the concepts have not yet been introduced.
By allowing non-idiomatic code in the earliest exercises, students are able to take many smaller steps in familiar territory rather than a few big steps in unfamiliar territory.
The result is that they are able to reach the stage of idiomatic code more quickly and with less friction.

## Basic structure

Exercises are structured as a tree with an introductory exercise at the top as the starting point.
Later exercises teach concepts that depend on having understood concepts that are taught earlier.

## Porting and borrowing

It can be worth looking at how other language tracks have built out their concept exercises.
You can find examples of Concept Exercises from other language tracks [here](https://exercism.org/docs/building/tracks/stories).

That said, if you decide to use other exercises as a starting point for your own, be careful to ensure that the resulting exercise is about the concept as it exists in your language.
Sometimes concepts differ subtly, sometimes radically.
Sometimes concepts don't exist in other languages at all.

The syllabus, and therefore the concept tree, should represent the concepts that exist in this specific language.

Don't include concepts just because other tracks do.

In some cases it might be tempting to put a concept in because people often have to work around it by using concepts that do exist.
Rather than doing this, introduce the concept that the language _does_ use, and consider adding an exercise that explains how to use it in that type of situation.

For example, in Go there are no enums.
Instead the Go concept tree introduces constants, and teaches how to use constants in the type of situation where you might use enums in other languages.

## Asking for help

Don't hesitate to ask for help.
It's better to ask up front or while working on an exercise rather than discussing during code review.

On GitHub you can mention the team @exercism/learning-mode.
In Slack you can ask in the #learning-mode channel.
Please email hello@exercism.org if you need an invitation to our Slack workspace.

## Getting started

Our experience has taught us that the most pragmatic way to develop a syllabus is to grow the concept tree organically, starting with the simplest concepts.
We don't have to design everything up front, and it's actually generally useful to not think too far ahead.

We start with the bare minimum of concepts — those that are most fundamental to writing **anything** in the language.
We also try to start with concepts that are most familiar to the average developer.
Familiar is good.
Familiar is not confusing.

Remember, while the endpoint is to write idiomatic code, the stepping stones to get there are not always idiomatic.
Using what is familiar — even if it is not a great example of code in that language — helps move a student more quickly toward the goal of code that is more typical of the language.

### Developing the first exercise

Rather than trying to map out the entire concept tree up front, just start with the first exercise.
The goal of the first exercise is to allow the student to start learning with the least amount of friction as possible.
They are taking the very first step towards getting familiar with what code in this language looks like.
They might write a small piece of code, or perhaps just make a couple of additions to a stub in order to complete the exercise.
The students have already solved "Hello, World!" in order to access this exercise.
But in "Hello, World!" they are only changing the wording.
All of the syntax of the language might still be unfamiliar.
Try to optimize for a quick win and getting students familiar enough with the bare necessities of syntax to be able to move forward confidently.

Read more about [developing the first exercise](/docs/building/tracks/syllabus/first-exercise.md).

### The next exercises

The first exercise should unlock a handful of exercises that introduce fundamental concepts.
These will be things like primitives or basic types and simple operations on those types.

Read more about [developing the next exercises](/docs/building/tracks/syllabus/next-exercises.md).

### And then what?

This is where it often starts getting interesting.
There is so much you _could_ introduce at this point.
How do you decide what concepts to tackle next?

It kind of doesn't matter.
As long as you start somewhere that seems reasonable, it will be fine.

Read more about what we think "reasonable" means in the context of [expanding the concept tree](/docs/building/tracks/syllabus/expanding.md).

## Do not convert practice exercises

A good Concept Exercise is extremely focused, and ideally teaches only one concept.
There will usually be only one expected approach to solving it.
This is in contrast to Practice Exercises, which are open ended and lend themselves to exploration.

A good Concept Exercise is usually a bad Practice Exercise, and vice versa.
Since the goals of Practice Exercises and Concept Exercises are completely different, we do not take Practice Exercises and convert them into Concept Exercises.
We write all Concept Exercises from scratch or base them on stories that were explicitly crafted for the purpose of teaching simple concepts.

## We encourage hand-waving

Sometimes you'll feel like there is a deadlock.
Concept A requires understanding concept B, and B requires understanding A.

In this case simplify.
Hand-wave over some complexity in one so that you can get students familiar with the other.
It's perfectly fine to say that something will be introduced in more depth later, and that for now the student just needs to understand this one bit.

Concepts are understood more deeply in stages and over time.

## Selecting stories

A concept exercise always has a story.

If you're forking an exercise from another track, then the exercise will already have a story.
In that case, you're all set.

To see if there are any existing stories you can use or exercises you can fork, check out the [list of stories](docs/building/tracks/stories).

If you have a concept but no story then our recommendation is to write a small, simple code example that uses the concept that you're introducing.
Then reverse engineer a story onto the code.
Keep the story stupidly simple.
It doesn't have to be good fiction.
It doesn't need a strong plot or character development.
It can be just a couple of lines long.

Bounce ideas for stories with the Exercism team.
We have a lot of experience coming up with suitable stories.

Once you have a story you will likely need to tweak the code a bit to get it to fit the story.

## Contributions from the community

Working on a syllabus involves two separate but intertwined activities:

1. Syllabus design: selecting and ordering concepts
2. Exercise implementation: writing documentation and creating exercises to teach those concepts

We've found that it's both fun and enriching to get the wider community to contribute to implementing exercises.
The syllabus design itself, though, is easier to tackle with a small team of contributors who are all engaged in building up an understanding of the full syllabus with all of its intricacies.

That said, we recommend that the syllabus design team implements the first five or six concepts first, before opening up for community contributions.
This helps ensure that the people on the core team of syllabus designers understand the process themselves before having to review pull requests from people in the broader community.

It's also easier to create issues for these higher-order concepts and tends to be more fun for community members to work on them, since there are fewer constraints to worry about.

## Creating issues

We still haven't figured out how to best create issues for creating concept exercises.

In some tracks we've tried creating separate exercises for the concept itself and the exercise.
In others we've tried making issues that have a checklist to work through.
Overall, we think this is still too intimidating, and we'd like to find a better way.

Please talk to us about the process as you start making issues, and we will do our best to help figure out how to proceed.

We will update the documentation as we learn better ways of tackling this.
19 changes: 19 additions & 0 deletions building/tracks/syllabus/expanding.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Syllabus - Expanding

Once you've built a few concept exercises it becomes easier to expand the syllabus.
This is because you now have access to more concepts that you can build on.

The two main ways that we expand a concept tree are to:

1. build on an existing concept (e.g. `time` => `timezones`)
2. introduce a new concept that depends on a concept that has already been introduced (e.g. `classes` => `interfaces`)

If you're at a loss for what to choose next, take a look at one or two of the simplest practice exercises that exist for your track.
Identify the concepts that are used, and pick one that hasn't been covered yet in the syllabus.

You might discover that the exercise you're working on requires understanding a concept that hasn't been introduced yet.
Just make a note of it and finish the exercise with the assumption that the student already understands the missing concept.
Remember to set the status of the exercise to `wip`, as having gaps or jumps in the concept tree will be very confusing to students who are unfamiliar with the language.

It's worth taking a look at other tracks to see how they've structured their syllabuses.
For example the [Elixir track](https://exercism.org/tracks/elixir/concepts) has a really nice syllabus progression.
28 changes: 28 additions & 0 deletions building/tracks/syllabus/first-exercise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Syllabus - The first exercise

The first exercise should cover the concept `basics`, and it should have no prerequisites.
It should provide only enough information to allow the student to solve the exercise at hand.

Many tracks have already implemented an exercise covering `basics`.
To familiarize with what is commonly taught in such an exercise, we recommend that you go sign up to a few different tracks that have Learning Mode, and solve the first concept exercise.

Each language is different, and you might find that you need to introduce more than other tracks do, or less.
For example, if you need to compile a program to get it to work, this is something that you'll want to mention in the introduction to the exercise.

Other things that are often covered within the `basics` exercise are:

- function or method definitions
- calling functions
- passing arguments to functions
- assigning a value with a name (variables and/or constants)

Use as few data types as possible.
If you can manage, use only integers, as their notation is the same across most languages and will be well known to virtually everyone.

If there's a track for a language that is similar to yours, go ahead and check if you can fork their exercise and use it as a starting point.

Aim to be concise; you don't want to overload students with information.
The introduction should explain _just enough_ that the student can look at the code and identify what the different parts are.
They don't need a deep understanding of any of it, but they should also not be left wondering what something is.

The student should only need to actively _use_ one or two concepts.
33 changes: 33 additions & 0 deletions building/tracks/syllabus/next-exercises.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Syllabus - Next Exercises

Having implemented your first concept exercise, the next few exercises should build on that.

We like to have three to five exercises that have no prerequisites other than the `basics` concept.

Good options are the core primitives or data types of your language.
E.g. booleans, basic numeric types, strings, and atoms.

It's worth checking other tracks' concept exercises to see if there are any that are appropriate for your track.

Note that introducing a concept doesn't mean that you need to explain it fully in all its glory.
You can always defer complexity.
The language might have a dozen different numeric types that are useful in different scenarios.
The exercise can simply mention that there are others while introducing only the most commonly used integer type and most commonly used floating-point type.

Some core data types are too complex to introduce directly.
For example strings might be lists of chars.
In such a case you would need to defer the introduction of strings, and design a concept exercise for chars and another for lists.
Then you can add an exercise for strings that has both of those exercises as prerequisites.

Sometimes while working on an exercise you will realize that it's more complex than you expected.
That's totally fine.
Make a note of the concept that needs to be taught as a prerequisite.
Then pretend that such an exercise exists, and finish the exercise you're working on with that simplification in mind.
Then go back and create a new exercise for the prerequisite concept.
Remember to mark the exercise as `wip` until the prerequisite exercise has been added.

Another thing that can happen at this point is that you find that you have cyclical dependencies.
You need to introduce two concept, but each concept relies on the other.
In this case you may be able to use a stub.
Then you can explain that the dependent concept exists, but reassure them that they don't need to understand it yet.
Another option would be to give a bare minimum of an introduction, enough for the student to get past the hurdle, while reassuring that the concept will be covered in more depth later.

0 comments on commit ba3eba3

Please sign in to comment.