exercism / v3

The work-in-progress project for developing v3 tracks
https://v3.exercism.io
Other
170 stars 162 forks source link

[C#] Add new Concept Exercise: arrays #33

Closed ErikSchierboom closed 4 years ago

ErikSchierboom commented 4 years ago

This issue describes a new arrays exercise that should be added to the v3 C# track.

Goal

The goal of this exercise is to teach the student how the concept of collections is implemented in C#. We'll teach the student about collections by having the student work with one specific type of collection, namely the array. The students will learn to define arrays, iterate over array items, access items by index, and more.

Of the many available C# collection types, we chose to use the array collection type as the first collection type students will be taught for the following reasons:

Learning objectives

Out of scope

Concepts

This Concepts Exercise's Concepts are:

Any data types used in this exercise (e.g. strings) should also be added as prerequisites.

Prequisites

This Concept Exercise's prerequisites Concepts are:

Any data types used in this exercise (e.g. strings) should also be added as prerequisites.

Resources to refer to

Hints

After

As this is an introductory exercise, we should take care not to link to very advanced resources, to prevent overwhelming the student.

Representer

This exercise does not require any specific representation logic to be added to the representer.

Analyzer

This exercise could benefit from having an analyzer that can comment on:

Implementing

If you'd like to work on implementing this exercise, the first step is to let us know through a comment on this issue, to prevent multiple people from working on the same exercise. If you have any questions while implementing the exercise, please also post them as comments in this issue.

Implementing the exercise means creating the following files:

languages
└── csharp
    └── exercises
        └── concept
            └── arrays
                ├── .docs
                |   ├── after.md
                |   ├── hints.md
                |   ├── instructions.md
                |   └── introduction.md
                ├── .meta
                |   ├── design.md
                |   └── Example.cs
                ├── Arrays.csproj
                ├── Arrays.cs
                └── ArraysTests.cs

Step 1: add .docs/introduction.md

This file contains an introduction to the concept. It should be explicit about what the exercise teaches and maybe provide a brief introduction to the concepts, but not give away so much that the user doesn't have to do any work to solve the exercise.

Step 2: add .docs/instructions.md

This file contains instructions for the exercise. It should explicitly explain what the user needs to do (define a method with the signature X(...) that takes an A and returns a Z), and provide at least one example usage of that function. If there are multiple tasks within the exercise, it should provide an example of each.

Step 3: add .docs/hints.md

If the user gets stuck, we will allow them to click a button requesting a hint, which shows this file. We will softly discourage them using it. The file should contain both general and task-specific "hints". These hints should be enough to unblock almost any student.

Step 4: add .docs/after.md

Once the user completes the exercise they will be shown this file, which gives them any bonus information or further reading about the concept taught.

These files are also all described in the [concept exercises document][docs-concept-exercises].

Step 5: update languages/csharp/config.json

An entry should be added to the track's config.json file for the new concept exercise:

{
  ...
  "exercises": {
    "concept": [
      ...
      {
        "slug": "arrays",
        "uuid": "b6c532c9-1e89-4fbf-8f08-27f5befb5bb8",
        "concepts": ["arrays", "foreach-loops"],
        "prerequisites": ["for-loops"]
      }
    ]
  }
}

Step 6: adding track-specific files

These files are specific to the C# track:

Check out the floating-point-numbers exercise for an example on what these files should look like.

Step 7: update the general concept document

Add the exercise to the concept's shared document's ## Implementations section (example).

Step 8: updating list of implemented exercises

Step 9: add .meta/design.md:

This file contains information on the exercise's design, which includes things like its goal, its teaching goals, what not to teach, and more ([example][meta-design]). This information can be extracted from this GitHub issue.

Inspiration

When implementing this exericse, it can be very useful to look at already implemented C# exercises like the strings, dates or floating-point numbers exercises. You can also check the general array concept documentation to see if any other languages have already implemented an arrays exercise.

MarkusReynolds1989 commented 4 years ago

I'll open up that other issue but I'll go ahead and work on this too. Would you please assign this to me?

MarkusReynolds1989 commented 4 years ago

https://github.com/markusreynolds1989-fork/v3/tree/arrays/languages/csharp/concept-exercises/arrays I have some initial concepts in Arrays.cs

ErikSchierboom commented 4 years ago

@MarkusReynolds1989 Done. I'll look at the initial concepts tomorrow

ErikSchierboom commented 4 years ago

@MarkusReynolds1989 It might be easier to review if you were to create a (draft) PR. Could you do that?

MarkusReynolds1989 commented 4 years ago

So in my mind the input of the methods is either the static array that we can provide or null. I put null because I want to make sure that the students are learning to test for edge cases. We could change this to where the student writes their own array, and we could have them make up their own hours worked for the week and then adjust the tests to fit that pretty easily. I think overall them writing their own array would probably be a better fit.

robkeim commented 4 years ago

Cool stuff @MarkusReynolds1989!

If we're looking to demonstrate array access as well, maybe we could have a method:

public int GetHoursWorkedPerDay(DayOfWeek dayOfWeek)

The downside of that approach would be require a dependency on enums for this exercise. If we want to avoid enums, we could always have the day of the week be an int passed and then you'd have a simple index after checking for out of bounds values.

ErikSchierboom commented 4 years ago

I put null because I want to make sure that the students are learning to test for edge cases.

I see, but I'd rather prefer having a separate exercise for error handling an a separate one for dealing with null's (we could even teach the fancy C# 8 nullable features).

The downside of that approach would be require a dependency on enums for this exercise.

Yeah, and the enums exercise currently requires some more advanced Concepts (generics and out parameters). So that might not be the best of options unfortunately :( An alternative would be to simplify the enums exercise.

I think overall them writing their own array would probably be a better fit.

Yeah, we can enforce this by having a method that will return an array. Students will then be forced to write an array.

MarkusReynolds1989 commented 4 years ago

I put null because I want to make sure that the students are learning to test for edge cases.

I see, but I'd rather prefer having a separate exercise for error handling an a separate one for dealing with null's (we could even teach the fancy C# 8 nullable features).

The downside of that approach would be require a dependency on enums for this exercise.

Yeah, and the enums exercise currently requires some more advanced Concepts (generics and out parameters). So that might not be the best of options unfortunately :( An alternative would be to simplify the enums exercise.

I think overall them writing their own array would probably be a better fit.

Yeah, we can enforce this by having a method that will return an array. Students will then be forced to write an array.

Ah okay, then we can do away with all empty input tests and just really focus on testing the array the student writes and the other methods. How about this: Write an array that represents the hours you work every day for the week (when a week has 7 days and begins on Sunday)

int[] hoursPerDay = int[]{0,8,8,8,8,8,0};

then they write that array and the methods to operate on it, such as sum of hours, avg hours, and the index of the 2nd most hours worked or amount of hours worked on Friday.

ErikSchierboom commented 4 years ago

Write an array that represents the hours you work every day for the week (when a week has 7 days and begins on Sunday)

Yeah, I like that. So maybe we would have a stub method like this:

public static int[] RegularWorkWeek()
{
    throw new NotImplementedException("...");
}

Then we could indeed have the other methods take the hours array returned by the RegularWorkWeek method. A test would look like this:

[Fact]
public void HoursOnFriday()
{
     var hours = WorkingHours.RegularWorkWeek();
     var actual = WorkingHours.OnFriday(hours);
     Assert.Equal(8, actual);
}

Note that we'd have to use different hours in the array to force a correct implementation, but I feel like this could work.

One small note: we should try to make things use the least amount of math. So I feel the sum of hours (TotalHoursWorked) is fine, but I'd rather we'd not use the average.

@exercism/csharp what do you think?

MarkusReynolds1989 commented 4 years ago

I'm opening the floor to anyone with more method ideas to thoroughly test the array the student writes out. I like finding the sum and the index. What about a method that finds the first day where the most hours were worked? They could do that with a for loop with just using the built in Array.Sort -> .Reverse and getting the index of the first result.

ErikSchierboom commented 4 years ago

What about a method that finds the first day where the most hours were worked? They could do that with a for loop with just using the built in Array.Sort -> .Reverse and getting the index of the first result.

I like that! Really nice.

batibot323 commented 4 years ago

I'm opening the floor to anyone with more method ideas to thoroughly test the array the student writes out.

What about a method that would return a new array containing minutes worked instead of hours? That could be the next step after implementing the TotalHoursWorked(), to practice iterating over an array.

We can also test the use of .Length and making another array from an existing one by requiring to return an array that would only display Monday-Friday. This would be a step up from the HoursOnFriday() method.

NextNebula commented 4 years ago

I think to be more inclusive it is better to move to a predefined example. Not all students have a work week. Maybe they do not have a job, maybe they are students that do not see their study as work, maybe they have a very irregular job, etc. It is not needed for the exercise to ask students to think about that.

An example like this should be fine: Jane has a fixed work schedule, she works 8 hours on Monday, Tuesday and Thursday. On Wednesday and Friday, Jane works 4 hours. Saturday and Sunday Jane doesn't work.

Some exercises for methods can be.

public static int[] RegularWorkWeek()
{
    throw new NotImplementedException("...");
}
public static int TotalHoursWorked()
{
    var hours = WorkingHours.RegularWorkWeek();
    throw new NotImplementedException("...");
}
ErikSchierboom commented 4 years ago

@EarthlingRich Great suggestions!

robkeim commented 4 years ago

I really like the conversion to minutes worked because that tests iteration and forces the student to create a new array. Another way to test creating a new array would be to return a "sub" array of only the days during the week, or only the weekend days.

On small nit regarding the first day of the week, I think it makes sense to follow ISO-8601 and start the on Monday instead of Sunday: https://en.wikipedia.org/wiki/ISO_8601

NextNebula commented 4 years ago

I agree with the starting on Monday, makes more sense for where I live. It is good to follow a standard. But we should keep stating when the week starts, because this differs per area.

The conversion in minutes sounds like a good exercise for students to create a new array.

robkeim commented 4 years ago

But we should keep stating when the week starts, because this differs per area.

Yes, we'll definitely need to do that in any case

ErikSchierboom commented 4 years ago

BTW With #663 opened, we could consider depending on the enums-basic Concept for this exercise, to allow use of the WeekDay enum. Another option would be for the dates exercise to depend on the enums-basic Concept and then use one of the date-based enumerations (e.g. WeekDay).

MarkusReynolds1989 commented 4 years ago

Are we ready for me to write a new version of this based on what we discussed?

ErikSchierboom commented 4 years ago

I think so. Are the above comments clear?

ErikSchierboom commented 4 years ago

There is an open PR that creates an array exercise for JavaScript. It might be convenient to port that exercise instead of having to come up with everything ourselves, as much of the groundwork in that exercise can be re-used for a C# exercise (the theme/context), instructions, etc. For an example on how to do a port of an existing exercise, see this video. The JS exercise would need so minor changes, for example arrays in C# have a fixed length and don't in JavaScript, but we can work with that I think.

@MarkusReynolds1989 what do you think? Are you still interested in working on this exercise?

MarkusReynolds1989 commented 4 years ago

There is an open PR that creates an array exercise for JavaScript. It might be convenient to port that exercise instead of having to come up with everything ourselves, as much of the groundwork in that exercise can be re-used for a C# exercise (the theme/context), instructions, etc. For an example on how to do a port of an existing exercise, see this video. The JS exercise would need so minor changes, for example arrays in C# have a fixed length and don't in JavaScript, but we can work with that I think.

@MarkusReynolds1989 what do you think? Are you still interested in working on this exercise?

Hey Erik, I'll go ahead and just work on porting that exercise then, if there's a great example no reason to reinvent the wheel. I'll watch the video and work on that some time today.

ErikSchierboom commented 4 years ago

Awesome! This video is also a great one to watch.

ErikSchierboom commented 4 years ago

Having looked at the JavaScript exercise, I'm thinking that might actually be a better exercise to port to the C# lists exercise, as it will remove and add items.