Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New track progression model will require changes to the existing tracks #159

Closed
kytrinyx opened this issue Jun 25, 2017 · 51 comments
Closed

Comments

@kytrinyx
Copy link
Member

Over the past four years we've gotten some things right. Other things have been a struggle. Some things we never even thought to question. Since the new year @iHiD, @nicolechalmers, @ccare and I have been doing some intense rethinking of the underlying questions that Exercism is built on. The result of this was shared in #154, which links to a whole set of philosophical documents that we've added to our docs repository.

The next step is to take these ideas and insights and to turn them into user journeys, user flows, and wireframes. Thalamus's design process has a very tight loop between discussions, wireframes, and prototypes, so the result of this part of the process will be a straight-forward, no-frills Rails application that tests out the concepts and ideas that we've spent the past six months hashing out. Our goal with the prototype is to get the user experience out in front of people for feedback. The outcome might be that we discover things that we've fundamentally misunderstood and need to go back to the drawing board, or there might be a consensus that the prototype is the right direction. From there we might adopt it and iterate, or decide that the implementation needs to be tackled in a different way.

To quote @iHiD:

The key aim of this process is for us to understand whether all of the concepts and decisions we've made make sense, and whether the UI that we're designing "works" from a product and UX POV. The specifics of the tech that powers it is something I feel less concerned about, so I'm going for established harder-to-make-bugs-in tech, which Rails fits for me.

Changes to the Language Tracks

As you may have read in the Progression & Learning in Exercism document, we realized that one of the key pain points with the current track progression is that the exercises do not feel purposeful. While there is some sense that exercises get harder as you progress, there is no sense of a clear goal in sight. Worse, we add more exercises, which moves the goal post.

To make matters worse, there is no easy way to adjust this progression based on your individual needs. If you know one topic well, have no interest in another, and wish to explore a third, well—tough luck, really.

In order to support a more compelling learning experience, we have decided to structure the experience much like role playing games where there is a series of "core" exercises, each of which unlocks optional exercises exploring topics in more breadth or depth.

In other words, for the prototype we've got work to do in the language tracks in order to support this.

In the near term, we need to take the exercises that we have in a track, and provide just enough metadata that they will fit into the new structure.

In the longer term we hope that each track will take a careful look at the concepts and standard library of the language in question, and discover where we have little or no coverage, and make up new exercises that will help people become fluent with these areas of the language.

For the prototype, we're concerned with the near term, as we hope to have something for people to try out a few weeks from now.

The new structure will consist of:

  • a core set of exercises, which are worked through in order and cover key topics.
  • a secondary set of exercises that are unlocked by the core exercises. Each core exercise will unlock a number of secondary exercises. In the first version of the prototype, the secondary exercises unlocked by a given core exercise can be tackled in any order. We're considering whether it would be useful to also let secondary exercises unlock further secondary exercises.

Each exercise, therefore, needs metadata. This metadata will be in part curated (e.g. topics and difficulty), but also collated (e.g. average time to completion).

We made a change a while back to allow more metadata for each exercise in the track's config.json, but none of the metadata has been used directly by the application. Some tracks have added topics and difficulty, and have used this to reorder the exercises in the track. Other tracks have not added any additional metadata.

In order to prepare your track for the new track progression model, you'll need to do the following:

  • add topics to each exercise. We have a list of topics that you can use for inspiration, but this list is not exhaustive. The topics you choose should make sense for your language.
  • add a rough guess at the difficulty of each exercise.
  • choose 10-20 exercises to mark as core
  • give the core exercises an order
  • for all other exercises, mark them as unlocked_by one of the core exercises (identified by the slug)

As a first pass (and to avoid analysis paralysis) it would be completely fine to make the least difficult exercise that introduces a topic "core", and have it unlock all other exercises that cover that topic.

We will only include tracks that have made this transition in the prototype.

@exercism/track-maintainers does this make sense and sound doable?

@NobbZ
Copy link
Member

NobbZ commented Jun 25, 2017

I'm not quite sure if I understood correctly how the config.json shall look like later on.

Can you provide an example for an imaginary track having two exercises? One marked as core and another one unlocked by that?

@kytrinyx
Copy link
Member Author

@NobbZ That's a good question, and I'm open to suggestions on what the JSON should actually look like.

Perhaps something like this:

  "exercises": [
    {
      "slug": "hello-world",
      "core": true,
      "difficulty": 1,
      "topics": [
        "string comparison",
	"string concatenation"
      ]
    },
    {
      "slug": "hamming",
      "core": false,
      "difficulty": 2,
      "unlocked_by": "hello-world",
      "topics": [
        "string comparison"
      ]
    }
  ]

@petertseng
Copy link
Member

petertseng commented Jun 25, 2017

Don't forget to add an order to hello-world.

But this reminds me, would an order be necessary, if instead it uses the ordering of the array?


Be explicit about core?

Or say that:

  • If it has an order, we know it is core
  • If it has an unlocked_by, we know it is not core

and therefore core is not necessary to explicitly specify?

If it is explicitly specified, careful about people using one of the illegal combinations (anything that is the opposite of the two bullet points)

@NobbZ
Copy link
Member

NobbZ commented Jun 25, 2017

Ah, Okay, so currently the format isn't ironed out and as such there is probably no deadline set for the change? Then I had a fundamental misunderstanding in this part anyway.

Then I'd propose to beeing more uniform between the exercise-objects the following structure:

  "exercises": [
    {
      "slug": "hello-world",
      "parent": "$TRACK-core",
      "difficulty": 1,
      "topics": [
        "string comparison",
	"string concatenation"
      ]
    },
    {
      "slug": "hamming",
      "parent": "hello-world",
      "difficulty": 2,
      "topics": [
        "string comparison"
      ]
    }
  ]

Order across core-track and sidetracks could easily be determined from the order in the JSON then.

Another possibility were to split into separate lists, "core-exercises" which has a list like the one we currently have, no further changes needed and "side-exercises" which do have the "unlocked_by" key.

For the transition time, "exercises" could be left untouched and therefore understood by the old system further on without any problems (aside of maintaining two lists during transition).


edit

By "$TRACK-core" in the example I do not take that one literally, but suggest to interpolate $TRACK to that tracks slug. This will allow to have an exercise "core" later on while I think it will be unlikely that there will be an exercise "erlang-core" or "haskell-core" or anything…

@iHiD
Copy link
Member

iHiD commented Jun 25, 2017

I'm speaking here from the POV of the person who will probably be writing the code to parse these into the new structure. This is obviously one of those areas where there's no right/wrong and it's all opinion, but these are mine.

Ah, Okay, so currently the format isn't ironed out and as such there is probably no deadline set for the change?

We're aiming to launch the prototype in the 3rd week of July, so I imagine the cutoff date to be in the new version on launch will be around then.

"topics": [ "string comparison" ]

Could I request that these are underscored pls? (so string_comparison).

Order across core-track and sidetracks could easily be determined from the order in the JSON then.

I think having an explicit order would be ideal, as these will get saved into a DB with an explicit column, and so it would be nice to be able to check those 1-1.

Be explicit about core?

I'd rather be explicit about this (as per the point above). At a first glance I like the idea of of splitting it into core and side arrays, but in the situation where we want to change an exercise to be core/side, I prefer changing that field, rather than moving it into a different array.

@kytrinyx
Copy link
Member Author

there is probably no deadline set for the change?

There will be a deadline, yes, but I don't know what it is yet. We are just getting started on the prototype/wireframe work.

Once we get the format ironed out, we will have several weeks (at the very least) to get tracks into a state where they can be included in the prototype.

I expect that we can get the format ironed out in a week or so (based on previous discussions), and there will be several weeks after that to make the change.

@petertseng
Copy link
Member

Being explicit about the order gives us the ability to do fun things like have order: 2 in the array before order: 1, which would not be possible if it were implicit. I do not anticipate doing any such thing, just saying it's possible.

I anticipate that having to explicit about the order will hurt for a track reordering their exercises, adding an exercise anywhere except at the end of the order, or deleting an exercise anywhere except at the end of the order. It will be difficult to examine the resulting PR and make sure that all order numbers have been edited correctly.

That disadvantage would be mitigated with tool assistance in the form of configlet or the prediction that the above three operations will be rare.

@iHiD
Copy link
Member

iHiD commented Jun 25, 2017

@petertseng Helpful points.

I would also like something immutable in there that enables us to patch the db from this file. I don't think that should be slug (which feels like it could change) so I would propose adding a field called uuid to each exercise which is (shockingly) a uuid. I would also ideally rename the folders in git to include that, maybe in the form of #{slug}|#{uuid}. The slug helps maintain the human-readableness of the folder structure, but we can split on | (or whatever) and search on uuid.

That gives us guaranteed consistency with the ability to harmlessly rename etc. The data around exercises is going to be so much richer in nextercism (both in terms of qualitative stuff like difficulty, topics, etc but also quantitative (average attempts per exercise) and therefore I think maintaining that through exercism renames etc will be much easier if we're using an immutable identifier.

@stkent
Copy link

stkent commented Jun 25, 2017

"unlocked_by": "hello-world"

Should this be an array of unlockers, to accommodate exercises that touch multiple topics?

Also, is the intent that exercises within a 'side quest' will unlock each other sequentially, or that the entire set of exercises comprising a side quest will immediately unlock when the core exercise unlocks? (Sorry if this was already addressed and I missed it.)

@stkent
Copy link

stkent commented Jun 25, 2017

FWIW I have bandwidth to implement whatever we decide on in the Java and Kotlin tracks, so those can participate in the experiment.

@kytrinyx
Copy link
Member Author

Should this be an array of unlockers

No, I don't think so. The core exercises are linear—if you have to complete several of the core exercises before you get access to a secondary exercise, then the exercise is unlocked by the last of those exercises.

For the side quests we think that the right answer could be either or both, but from our current discussions we're probably going to start simple and unlock the entire set of side quests, which you can then select from (or get randomly). I'm not clear yet on the mechanics of it.

@stkent
Copy link

stkent commented Jun 25, 2017

if you have to complete several of the core exercises before you get access to a secondary exercise, then the exercise is unlocked by the last of those exercises.

Sorry, I was unclear here. I was imagining that one might be able to unlock a side quest exercise by completing any one of a set of core exercises. E.G. if I have a side quest exercise that touches on string comparison and generics, then we might want that exercise to be unlocked by completing either the core string comparison exercise, or the core generics exercise? I guess a related question is: can an exercise appear in more than one side quest? 🤔

@iHiD
Copy link
Member

iHiD commented Jun 25, 2017

The core exercises are sequential (and forced so). So we'll always know the order someone will complete them in. The side quests are unlocked by an exercise, not a topic. So we can always predict when a side exercise should be unlocked by a core exercise. Is that clearer or have I just added mud? :)

@stkent
Copy link

stkent commented Jun 25, 2017

Ah, the forced ordering of the core exercises is something I didn't parse before, but do now. That makes sense. I think my question regarding whether or not a side exercise can appear in multiple side quests is still valid though?

@iHiD
Copy link
Member

iHiD commented Jun 25, 2017

side quest == side exercise.

I think we need to work on the nomenclature for that still!

@kytrinyx
Copy link
Member Author

I think my question regarding whether or not a side exercise can appear in multiple side quests is still valid though?

A secondary exercise becomes available at a certain point in time (unlocked by having done a particular core exercise). Once it's available, it's available—it isn't necessarily tied (in the user experience side of things) to a particular core exercise.

@stkent
Copy link

stkent commented Jun 25, 2017

Ah, ok. So as a user who has unlocked some side exercises, there's no "mini-track" for a topic that defines an ordering for those side exercises; they are just a blob of exercises I can e.g. filter by topic and manually fetch as I see fit?

@kytrinyx
Copy link
Member Author

there's no "mini-track" for a topic that defines an ordering for those side exercises

No, at the moment we're not considering ordering for the secondary exercises. We haven't settled on the user interface for how you select exercises, but yeah—there will likely be some way to select the ones you're interested in.

@rbasso
Copy link

rbasso commented Jun 25, 2017

I just caught the discussion in the middle - so I may be missing something - but this is how I think the exercise's dependencies could be modeled:

Requirements

These are two fundamental properties desirable to have a sane implementation:

  1. The availability of an exercises may be conditional on completion of other exercises.

  2. There must be at least one possible order to solve all the exercises.

Some choices

Single dependency

If each exercise depends on at most one exercise, to respect property 2, the track's structure must be an acyclic, connect graph, i.e., a tree, or a forest.

A simple way to represent it would be to ignore the ordering in the exercises key in config.json and add the following:

"dependencies": {
  "leap": "hello-world",
  "food-chain": "beer-song"
}
  • leap depends on hello-world.
  • food-chain depends on beer-song.
Multiple dependencies

If the availability of an exercise can depend on completion of multiple exercises, we have the more general case of a directed acyclic graph.

"dependencies": {
  "leap": ["hello-world"],
  "beer-song": ["hello-world"],
  "house": ["hello-world"],
  "food-chain": ["beer-song", "house"]
}

Here food-chain would depend on beer-song and house. Indirectly, it would also depend on hello-world, of course.

Alternative dependencies

if the availability depends on completing any of the dependencies, we still have a directed acyclic graph, but in this case we have to consider that nodes without incoming arrows as always available, to satisfy property 2.

The representation could be the same as in the previous case, just the
interpretation is different.

Alternative, multiple dependencies

This is the most generic solution I could imagine:

"dependencies": {
  "hello-world": [[]],
  "leap": [["hello-world"]],
  "bob": [["hello-world"]],
  "house": [["hello-world"]],
  "food-chain": [["house"] , ["bob", "leap"]]
}
  • hello-world has no dependencies.
  • food-chain depends on house or (bob and leap).

An exercise would be available, iff...

  • Its key in dependencies is missing or has value null. Edit: Bad idea!
  • Its key is present and at least one of the sets of exercises is complete.

This would be more verbose than other representations, but it allows greater flexibility. Besides allowing representation of the proposed core exercises and side tracks, it would create the opportunity to craft an even richer track's path-opening experience, if desired.

Also, the proposed representation would leave the exercises key untouched (Edit: allowing a really smooth transition), and converting the config.json to this new format could be done automatically with a custom script.

Some things, like a dependency on the number of solved exercises in a set, would still be very inconvenient.

Makes sense?

@stkent
Copy link

stkent commented Jun 26, 2017

No, at the moment we're not considering ordering for the secondary exercises. We haven't settled on the user interface for how you select exercises, but yeah—there will likely be some way to select the ones you're interested in.

Cool, I'm on the same page as you now I think; thanks for the clarifications, all!

@ErikSchierboom
Copy link
Member

ErikSchierboom commented Jun 26, 2017

I think maintaining that through exercism renames etc will be much easier if we're using an immutable identifier.
Good idea!

No, at the moment we're not considering ordering for the secondary exercises. We haven't settled on the user interface for how you select exercises, but yeah—there will likely be some way to select the ones you're interested in.
We can do lots of things here based on the metadata, e.g. display related exercises (which themselves could be ordered by difficulty) or display exercises of similar difficulty. Maybe even something like "you just finished exercises X, perhaps you might also like exercise Y"?

@rbasso Has some great questions! Is it true that the current situation is as follows:

  1. The "core" exercises are fixed and ordered.
  2. The "side quest" exercises are unlocked by completing one of the core exercises.

Is that correct?

@kytrinyx
Copy link
Member Author

@ErikSchierboom As far as I can tell, for right now, that is correct.

I'm sure that as soon as we start actually doing this we'll learn things, but our hypothesis is built around learnings from role playing games, and that's how it works there.

The thing about role playing games is that people don't know why they've got access to a side quest, and they might not even know it's a side quest. It's just that they have access to more exciting stuff.

I think we'll be calling out the difference more on Exercism.

@rpottsoh
Copy link
Member

@kytrinyx when a student enters a track for the first time (or any time for that matter) how will the list of available exercises appear to them?

  • Will those exercises that serve as launching points for quests appear (look somehow) different from other exercises in the list of available exercises that do not act as the start of a quest?
  • How will revealed exercises be inserted into the list of available exercises?
  • When a student enters a track will they be informed of the the total number of exercises that are available or only the number based on root level exercises or based on what root level exercises and which root level exercises have been completed.

I think my questions pertain mostly to how the exercises are presented to the student while they are navigating the site, but could be construed to how the exercises present for the CLI as well.

@kytrinyx
Copy link
Member Author

@rpottsoh All the visual stuff is being worked out by @nicolechalmers. These are great questions (that I, personally, don't have answers to at the moment). Nicole has probably spent time thinking about the trade-offs and implications and might have some ideas about where this will be headed, but I also don't want to suggest that she share until she has worked out the big questions for herself.

@Insti
Copy link

Insti commented Jun 30, 2017

As someone who is an experienced developer, will I be required to complete all the core exercises before I can get access to a particular problem I am interested in on a new track, or will all problems still be accessible via exercism fetch language slug

@iHiD
Copy link
Member

iHiD commented Jun 30, 2017

@Insti Yes :)

There are two distinctions here (I'll take me and ruby as examples):

  • I am an experienced developer starting out in Ruby.
  • I am an experienced Ruby developer doing the Ruby track.

As an experienced developer starting out in Ruby, everything is geared towards me learning in a structured way. Our research and understanding shows that this structured approach will tick my brain's reward centres, that the clear progression will give me something to aim for, stop me from feeling overwhelmed, and make me feel like I'm on the way to achieving my goals. Therefore it's important that I can't just arbitrarily pick and choose, otherwise we're back to having a track as a "basket of exercises" to play with rather than a structured learning approach.

As an experienced Ruby developer, getting through the core exercises should be pretty quick and easy (10mins - 30mins per exercise?) and they should be fun and interesting enough that I don't mind this. After each one, I get another ~10 harder exercises to choose from, and after the 10x10-30 min investment I have everything to hand. I get that this might be annoying in some ways, but I think the slight pain to go through 10 exercises before being able to access everything is easily outweighed by the benefits of Exercism being a learning platform rather than a code-golf platform, and I think striking for a middle group misses both goals.

@petertseng
Copy link
Member

petertseng commented Jul 14, 2017

I note that the key order does not appear for "core": false exercises. This seems good; it seems good to omit keys that add no value.

Let us suppose that, as planned, deprecated exercises appear in the exercises array with "active": false.

I assume that these inactive exercises will not be displayed on the website, and perhaps also not in exercism list.

In that case, shall these keys be removed from all inactive exercises? I am not seeing a reason to keep them.

  • difficulty
  • topics

Since it is still possible to fetch an inactive exercise by explicitly specifying it, I suppose that core and unlocked_by could still be useful for them.

There are two cases.

  • The API allows any exercise to be fetched if it is specified by name, regardless of whether the calling user has unlocked it.
    • In this case, core and unlocked_by are completely irrelevant, and they should be removed.
  • The API checks whether the calling user has unlocked the exercise.
    • In that case, what is the behaviour of a track with the following exercises in this order: exercise A (active core), exercise B (inactive core), exercise C (active core)?
      • I suppose the behaviour that seems most consistent is "one must complete all active core exercises preceding that exercise"
        • To fetch exercise B, one must complete exercise A, since B is a core exercise and the set of active core exercises preceding B is {A}.
        • To fetch exercise C, one must complete exercise A, since C is a core exercise and the set of active core exercises preceding C is {A}.
        • Under this behaviour, core is still useful and should be kept even for inactive exercises.
    • unlocked_by will behave the same way and should be kept even for inactive exercises.

@petertseng
Copy link
Member

petertseng commented Jul 14, 2017

There are two cases.

  • The API allows any exercise to be fetched if it is specified by name, regardless of whether the calling user has unlocked it.
  • The API checks whether the calling user has unlocked the exercise.

It's not my place to say which case will be true (since I'm not the one doing the actual work!), but I will take this time to advise that if the latter option is true:

  • As shown above, it forces the implementor of the API to do extra work.
  • It requires keeping core and unlocked_by keys for inactive exercises, when they could otherwise be removed.
  • It adds no value. The exercises may be fetched from Git anyway.

This discussion, of course, does not affect the list of exercises that are presented to the student.

@kytrinyx
Copy link
Member Author

I note that the key order does not appear for "core": false exercises. This seems good; it seems good to omit keys that add no value.

order does not appear for any of the exercises—we decided to let the core exercises be ordered by how they appear in the array.

I'm going to let @iHiD make the final call since he's knee-deep in the prototype for this.

That said, I think that it is safe to remove everything except uuid, slug, and active for deprecated exercises.

We will be using the config to write (meta)data about the exercise to the database—so for deprecated exercises, we can keep the topics in the database. If people have solved the exercise, we'll need to show it to them, but we're using Git for that, so we should be safe on that account.

I actually think that we could delete the exercise itself, and leave it in the config as "active": false (we would need to update configlet.

I do not think we need to keep the exercise available for people to solve after we deprecate it. If they really want it, they can go back in the git history of the repo to find it. It's not a use case that I think we should optimize for.

Since it is still possible to fetch an inactive exercise by explicitly specifying it, I suppose that core and unlocked_by could still be useful for them.

I think that in the new prototype, we should not allow people to fetch deprecated exercises.

Even if they have previously solved it, it is no longer available. We will show it to them on the site (they solved it, afterall), but it is no longer available for download. If they really want to, they can get it from the Git repo.

The API allows any exercise to be fetched if it is specified by name, regardless of whether the calling user has unlocked it.

No, the API will check that you have unlocked the exercise, and that it is active.

An open question for @nicolechalmers is how to display deprecated (solved) exercises on the site, and whether the display needs to be different depending on whether the exercise was a core exercise when they solved it or not.

Another open question is what happens when an exercise that was previously core gets moved to be a non-core exercise, and vice versa. For people who have not solved that exercise, that will be straight forward, but we probably need to think through what it will look like for people who solved it before it changed.

@iHiD
Copy link
Member

iHiD commented Jul 14, 2017

Hello. Great discussion :)

There's loads of points above. As @kytrinyx says, I'm deep in writing the code to this, so I'll try and summarise things as I see them / have coded them.

  1. The lifecycle of an exercise is [active] -> [deprecated]
  2. Once a user starts an exercise they should forever after be able to see the exercise, their solution, feedback, etc on the website, and should be able to show case it on their profile. Therefore deprecated exercise will still appear in places on the website and therefore still need their full array of keys (topics, difficulty, etc). The student doesn't care whether an exercise is deprecated or not - they just care that they've done it and want to feel proud of it.
  3. If a core exercise is deprecated and other non-deprecated exercises rely on it, we have a problem. configlet needs to fail the build in this case.
  4. If a core exercise is deprecated and other exercises that rely on it are set to rely on a different core exercise in the same PR, people who have completed the initial core exercise should still have access to the exercises they unlocked.
  5. Once an exercise is deprecated it will not appear for anyone who has not yet started it.
  6. The API checks that you have permission to download/submit an exercise and follows the rules above.
  7. We are removing the order key entirely and respecting the order of the exercises in the array.
  8. The only key that is optional is unlocked_by, which should not appear on core exercises.

I've already implemented all the points other than (3), which is on @kytrinyx's todo list with some other checking around uuids and things.

A point on the technical implementation that may make this clear. Whether you have permission to access an exercise is not determined at runtime (neither in the website or the API). Instead, when someone unlocks an exercise, a database record added noting that it has been unlocked. We then simply check for that record during runtime. This solves a lot of the problems of "what happens when X" because the decision has already happened in the student's flow. The one gotcha in this has been making sure that new exercises that are added to git have these "unlocked records" created for the correct people when the config is parsed into the database.

It adds no value. The exercises may be fetched from Git anyway.

We are working on the basis that value of exercism is in the feedback. You cannot submit a solution to an exercise that you do not have permission to submit, so this is guarded at this point.

I'd finish by saying that I have strong opinions on how this should work in the scope of the product/website/API, but consider my opinions on how it should work in the config.json relatively irrelevant as the core thing with the JSON file is that it needs to make lives of the track maintainers as easy as possible. I think/hope we've done that in the structure that we've come up with so far! :)

Final final note: We're getting really close to opening up the prototype to all the maintainers, which we're massively excited about :)

Hope that adds some clarity and is helpful. Happy to debate :)

@kytrinyx
Copy link
Member Author

Therefore deprecated exercise will still appear in places on the website and therefore still need their full array of keys (topics, difficulty, etc)

@iHiD We use the config.json to import exercises into the database. If, on deprecation of an exercise the only thing we change in the database is the active status, then I think it would be safe to remove all the other data from the config.json. The maintainers don't need to maintain that data anymore, and we have it in the database so we can show it to the users.

I would recommend that we consider making all but the slug, uuid, and active optional for deprecated exercises.

@iHiD
Copy link
Member

iHiD commented Jul 14, 2017

@iHiD We use the config.json to import exercises into the database.

We also use config.json to update exercises in the database. So if you change difficult or topics in the json, the database should update to reflect that. I perceive the config.json files to be the single point of truth in everything. Therefore removing keys from that file should also remove them from the database.

The other option would be to say that an exercises config is immutable, but since we've already said things like the slug should be mutable, I think topics etc should be too.

@kytrinyx
Copy link
Member Author

We also use config.json to update exercises in the database.

Agreed.

So if you change difficult or topics in the json, the database should update to reflect that.

Agreed. Everything except the uuid is mutable, that's why we have it.

Therefore removing keys from that file should also remove them from the database.

Not necessarily. I would be perfectly content if our tooling knew that deprecation of exercises meant only flip the active toggle, don't change any of the other data.

So the question that I have is this: how much does it improve maintainers' lives if we let them delete the extraneous data?

If it's a wee bit, then it might not be worth the extra logic in the importer. If it's a lot, then it is.

@iHiD
Copy link
Member

iHiD commented Jul 14, 2017

Not necessarily. I would be perfectly content if our tooling knew that deprecation of exercises meant only flip the active toggle, don't change any of the other data.

That's a great point. However, I would then prefer the flag to be deprecated, not active as we're adding meaning (such as "ignore other keys") because it's "deprecated". There might be a future state that we're not considering which doesn't have those same rules, and therefore I would edge towards being explicit that we're deprecating the exercise, not that it's just inactive.

In the database side, we'll still have active: true/false, but the importer can understand the rule-set for deprecated and apply it accordingly. I'd be happy with that.

@kytrinyx
Copy link
Member Author

However, I would then prefer the flag to be deprecated, not active as we're adding meaning (such as "ignore other keys") because it's "deprecated".

That makes sense to me.

I'll remove the active key, and only have the deprecated key on deprecated exercises.

@kytrinyx
Copy link
Member Author

OK, I've updated the PRs for Haskell, Erlang, Rust, and Groovy.

@petertseng
Copy link
Member

Although I had based some opinions off of incorrect assumptions (that 1. deprecated exercises would not be visible, but 2. they would be downloadable), it seems that y'all are happy with the deprecated solution.

It is indeed a bit of a shame that config.json will no longer represent the source of truth, but at least its untruthiness is limited to the deprecated exercises.

Ultimately I predict it will not matter that much to me. It would have bugged me if unnecessary keys remained in the file, but it appears arguments could have been made that all keys were in fact necessary. But I am of course happy to have to specify less information for those deprecated exercises. And some of them were deprecated before difficulties or topics existed, so we had no information to fall back on either!

Thanks for the discussion and resulting work!

@kytrinyx
Copy link
Member Author

It is indeed a bit of a shame that config.json will no longer represent the source of truth, but at least its untruthiness is limited to the deprecated exercises.

We ended up discussing further, and decided that the config.json will, in fact, be the source of truth. Deprecated exercises will still be accessible to people who have done them, but their appearance will change a bit, and they will be visibly marked as deprecated.

Thanks, everyone, for discussing! We would not gave gotten to the bottom of this without digging into all the details and trade-offs.

@stevensonmt
Copy link

Curious if it will be possible to fetch exercises based on topic? For instance if someone is stuck on a particular concept they might want to address all problems related to that concept even if there are intervening exercises in the track order. I think this touches on the flexibility for more experienced devs (which I am certainly not) that @Insti was getting at. Or even for formal educators who want to use exercism for their students but want to direct the curriculum in line with their own syllabus or textbook.

@iHiD
Copy link
Member

iHiD commented Jul 20, 2017

@stevensonmt Yep! :)

You might be interested to read the document we wrote on progression (if you've not already), which talks about this a little. Fundamentally there will be a "core" exercise for each topic and completing it will unlock other exercises on the same topic. You can then filter on a topic to find exercises that might be useful to you.

Each topic has it's own progression bar, which will look something like this:

screen shot 2017-07-16 at 22 02 26

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests