Skip to content
This repository has been archived by the owner on Feb 16, 2019. It is now read-only.

Allow a Track to define an exercise that is does not have a language-independent definition #22

Closed
IanWhitney opened this issue Jan 17, 2017 · 7 comments

Comments

@IanWhitney
Copy link

IanWhitney commented Jan 17, 2017

Over in Rust (exercism/rust#248) we are trying to add some supplemental exercises to Luhn. These are Rust specific and don't need files to exist in x-common.

@petertseng noted that this approach breaks Trackler. And, indeed, my goofing off in the console backs that up.

The issue here (as far as I can see) is that Problem expects there to be metadata and throws errors if there's not.

Is this a case we could solve with some NullObject pattern love? If I refactored the metadata method to return a NullMetadata instead of nil, could tracks then implement their own exercises without putting noise files in x-common?

Or is there complexity/design/etc. that I'm missing here?

@Insti
Copy link
Contributor

Insti commented Jan 17, 2017

I think this is a good idea.

It would not surprise me if there were other side-effects of doing this, but I don't have it all in my head at the moment, so can't think of anything specific. (Maybe some stuff in x-api). Whatever they are, we should be able to fix them as we find them.

@kytrinyx and I recently had a discussion* about trackler assumptions and the requirement for a metadata.yml to exist in x-common. So I'd be interested in hearing her opinion on this one.

* I'm having great difficulty finding it again, it may have been attached to a commit that got orphaned.

@petertseng
Copy link
Member

I'm having great difficulty finding it again

Hello #6 (comment)

@Insti
Copy link
Contributor

Insti commented Jan 17, 2017

Yes that's the one. Thanks @petertseng.

The main problem there was that x-api was using trackler's test fixtures, and the lack of a metadata.yml file was causing problems for the x-api tests.

I am more sympathetic to the reasoning behind that decision now, but I still think it is wrong, although I have not found the time to fix it yet, thus becoming part of the problem.

I think the main takeaway is, make sure you test how the changes affect x-api too.

@petertseng
Copy link
Member

petertseng commented Jan 17, 2017

I wondered if exercism/problem-specifications#352 was relevant, but I don't know if such an F# exercise ever materialised.

I will comment on exercism/problem-specifications#352 with an aside relevant to that issue but not this issue.

exercism/exercism#3113 also speaks briefly of language-specific exercises.

IanWhitney pushed a commit to IanWhitney/trackler that referenced this issue Jan 18, 2017
This is a prepatory refactoring for exercism#22

No functional changes introduced in this change.

I'm extracting the concepts of creating and reading the metadata file
out of Problem and into a new Metadata class. This means I now know the
API that any metadata-like class will have to support.
ErikSchierboom pushed a commit to exercism/problem-specifications that referenced this issue Jan 19, 2017
At the time it was added (#97), indeed [Haskell][haskell] was the only
implementing track, and it was marked Haskell-specific.

However, the [Scala][scala] track has also implemented this exercise.
I predict it is confusing for Scala students to see "Haskell specific"
in the list of the Scala exercises. The proposal is to change it to
"specific to languages with immutable data".

[haskell]: exercism/haskell#84
[scala]: exercism/scala#157

Lenses can be a fit for any language that has immutable data and data
structures that can be nested.

In such a language, updating a deeply-nested field can be a lot of work,
but made easier with lenses. This exercise demonstrates the use of
lenses and is applicable to **any** language with immutable data, not
just Haskell.

The alternative considered was to use "functional programming" specific,
but the term "functional programming" is a little too broad. It's
altogether possible that a functional programming language could have
mutable data and a non-functional programming language could have
immutable data, so let's be precise about where lenses are helpful.

As of this writing, I do not believe any other exercise is
language-specific. Questions to this effect have been asked in:

* #352
* exercism/exercism#3113

If you are curious about having language-specific exercises, you may be
interested in exercism/DEPRECATED.trackler#22.
@IanWhitney
Copy link
Author

@kytrinyx, I'm not sure if I'm going down a rabbit hole that will end in tears. And I think this question can only be answered by you.

As evidenced by little PRs to date, I've been slowly digging into this and seeing what needs to be done. A problem I'm having is that it's hard to see exactly what effect a change to Trackler will have downstream. From what I can tell, it's only used by x-api and exercism.io.

But, since those two projects drive everything, affecting them can have big consequences.

To help me see what effects this change could have, I put together an outline of the current behavior of Trackler objects and how, if at all, that would change.


Core Trackler Methods

Trackler.problems

  • Current behavior: Returns a Problems collection that contains all problems in the common directory
  • Proposed behavior: Unchanged

Would it contain track-specific problems? No.

Trackler.tracks

  • Current behavior: Returns a Tracks collection that contains all language tracks in the tracks directory
  • Proposed behavior: Unchanged

Trackler.implementations

  • Current behavior: Returns a Hash. The key is a problem slug, the values is an array of all tracks that implement that problem.
  • Proposed behavior: Same structure, but if a track implements a track-only problem, it would be contained in this Hash. So, in the example we would now have
{..."rust-only" => [<rust implementation object>]...}

Trackler.implementations['rust-only'] would return a an array with a single implementation object.

Trackler.todos

  • Current behavior: Returns a Hash. The key is a track, the value is an array of common problems that the track does not implement.
  • Proposed behavior: Unchanged

Would it contain track-specific problems? No. Trackler.todos['rust-only'] would return nil.

Track methods

Track#implementations

  • Current behavior: Returns an Implementations collection of all problems defined in the track's config.json.
  • Proposed behavior: Unchanged, though some implementations will now only exist in that track.

Will it contain track-specific problems? Yes.

Track#problems

  • Current behavior: Returns an array of Problem objects that the track implements, defined by the track's config.json.
  • Proposed behavior: Unchanged, though some problems will now only exist in that track.

Will it contain track-specific problems? Yes.

Problem methods

Problem methods behave the same. The one difference is that the metadata and description files and their Repo URLs may now come from the track, not the x-common repository.


If that doesn't raise alarm bells, then I'll keep poking at this. But if any of those changes make you think, "Wait, that will break everything!" then I'll reconsider.

@kytrinyx
Copy link
Member

From what I can tell, it's only used by x-api and exercism.io.

This is correct. I'm also using it in a personal experiment to set Exercism exercises up to be compatible with GitHub classroom, but I'm totally OK with breaking that.

But, since those two projects drive everything, affecting them can have big consequences.

Yeah, but if we're careful I think it's OK.

If that doesn't raise alarm bells, then I'll keep poking at this.

That doesn't raise alarm bells. The one thing that comes to mind is that when we have the implementation, we often use the slug of the implementation to look up the problem in Trackler.problems. I think if we let the implementation hold on to a reference to a problem (or copy of one, whatever), then this would be straight forward to fix. It would either hold on to a track specific one, or a common one.

IanWhitney pushed a commit to IanWhitney/trackler that referenced this issue Feb 9, 2017
As mentioned in exercism#22

```
Trackler.problems

Current behavior: Returns a Problems collection that contains all
problems in the common directory

Proposed behavior: Unchanged

Would it contain track-specific problems? No.
```

and

```
Trackler.implementations

Current behavior: Returns a Hash. The key is a problem slug, the values
is an array of all tracks that implement that problem.

Proposed behavior: Same structure, but if a track implements a
track-only problem, it would be contained in this Hash. So, in the
example we would now have

{..."rust-only" => [<rust implementation object>]...}

Trackler.implementations['rust-only'] would return a an array with a
single implementation object.a
```

and

```
Trackler.todos

Current behavior: Returns a Hash. The key is a track, the value is an
array of common problems that the track does not implement.

Proposed behavior: Unchanged

Would it contain track-specific problems? No.

Trackler.todos['rust-only'] would return nil.
```

These tests exercise these behaviors
@IanWhitney
Copy link
Author

With the merge of #24, this issue is fixed.

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

No branches or pull requests

4 participants