Skip to content

Commit a03e0a9

Browse files
ErikSchierboomee7
andauthored
Add articles documentation (#406)
Add articles documentation Co-authored-by: ee7 <[email protected]>
1 parent f182326 commit a03e0a9

File tree

7 files changed

+289
-94
lines changed

7 files changed

+289
-94
lines changed

building/config.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,13 @@
562562
"title": "Approaches",
563563
"blurb": "Learn how to write approaches for exercises"
564564
},
565+
{
566+
"uuid": "362853a0-dc4a-43ee-abbb-d4a14cb5b5bb",
567+
"slug": "tracks/articles",
568+
"path": "building/tracks/articles.md",
569+
"title": "Articles",
570+
"blurb": "Learn how to write articles for exercises"
571+
},
565572
{
566573
"uuid": "8db530bb-e11b-4497-b088-5b4c997e09a2",
567574
"slug": "tracks/presentation",

building/configlet/lint.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,102 @@ The `config.json` file should have the following checks:
322322
- The `"test_runner"` key is optional
323323
- The `"test_runner"` value must be a boolean
324324

325+
### Rule: exercises/{concept|practice}/&lt;slug&gt;/.approaches/config.json is valid
326+
327+
- The file's presence is optional, unless there is a `introduction.md` or a sibling directory
328+
- The file must be valid JSON
329+
- The JSON root must be an object
330+
- The `"introduction.authors"` key is optional
331+
- The `"introduction.authors"` value must be an array
332+
- The `"introduction.authors"` values must be non-blank strings¹
333+
- The `"introduction.authors"` values must not have duplicates
334+
- The `"introduction.authors"` values are treated case-insensitively
335+
- If the `"introduction.authors"` array is non-empty, there must be a non-empty `introduction.md` file
336+
- The `"introduction.contributors"` key is optional
337+
- The `"introduction.contributors"` value must be an array
338+
- The `"introduction.contributors"` values must be non-blank strings¹
339+
- The `"introduction.contributors"` values must not have duplicates
340+
- The `"introduction.contributors"` values are treated case-insensitively
341+
- If the `"introduction.contributors"` array is non-empty, there must be a non-empty `introduction.md` file
342+
- Users can only be listed in either the `"introduction.authors"` or `"introduction.contributors"` array (no overlap)
343+
- The `"approaches"` key is optional, unless there is a sibling directory present (which contains the approach' files)
344+
- The `"approaches"` value must be an array of objects
345+
- The `"approaches[].uuid"` key is required
346+
- The `"approaches[].uuid"` value must be a unique version 4 UUID string⁶
347+
- The `"approaches[].uuid"` value for each concept must never change
348+
- The `"approaches[].slug"` key is required
349+
- The `"approaches[].slug"` value must be a kebab-case string² with length <= 255
350+
- The `"approaches[].slug"` value must have a corresponding non-empty `<slug>/content.md` file
351+
- The `"approaches[].slug"` value must have a corresponding non-empty `<slug>/snippet.txt` file
352+
- The `"approaches[].name"` key is required
353+
- The `"approaches[].name"` value must be a Title Case string³ with length <= 255
354+
- The `"approaches[].blurb"` key is required
355+
- The `"approaches[].blurb"` value must be a non-blank string¹ with length <= 350
356+
- The `"approaches[].authors"` key is required
357+
- The `"approaches[].authors"` value must be a non-empty array
358+
- The `"approaches[].authors"` values must be non-blank strings¹
359+
- The `"approaches[].authors"` values must not have duplicates
360+
- The `"approaches[].authors"` values are treated case-insensitively
361+
- The `"approaches[].contributors"` key is optional
362+
- The `"approaches[].contributors"` value must be an array
363+
- The `"approaches[].contributors"` values must be non-blank strings¹
364+
- The `"approaches[].contributors"` values must not have duplicates
365+
- The `"approaches[].contributors"` values are treated case-insensitively
366+
- Users can only be listed in either the `"approaches[].authors"` or `"approaches[].contributors"` array (no overlap)
367+
368+
### Rule: exercises/{concept|practice}/&lt;slug&gt;/.approaches/&lt;approach-slug&gt;/content.md is valid
369+
370+
- The file's presence is required if a matching `"approaches[].slug"` entry exists in the `.approaches/config.json` file
371+
- The Markdown must conform to the [Markdown standards](/docs/building/markdown/markdown)
372+
- Links must be absolute (relative links are not allowed)
373+
374+
### Rule: exercises/{concept|practice}/&lt;slug&gt;/.approaches/&lt;approach-slug&gt;/snippet.txt is valid
375+
376+
- The file's presence is required if a matching `"approaches[].slug"` entry exists in the `.approaches/config.json` file
377+
- The snippet must have at most 8 lines
378+
379+
### Rule: exercises/{concept|practice}/&lt;slug&gt;/.articles/config.json is valid
380+
381+
- The file's presence is optional, unless there is a sibling directory
382+
- The file must be valid JSON
383+
- The JSON root must be an object
384+
- The `"articles"` key is optional, unless there is a sibling directory present (which contains the article' files)
385+
- The `"articles"` value must be an array of objects
386+
- The `"articles[].uuid"` key is required
387+
- The `"articles[].uuid"` value must be a unique version 4 UUID string⁶
388+
- The `"articles[].uuid"` value for each concept must never change
389+
- The `"articles[].slug"` key is required
390+
- The `"articles[].slug"` value must be a kebab-case string² with length <= 255
391+
- The `"articles[].slug"` value must have a corresponding non-empty `<slug>/content.md` file
392+
- The `"articles[].slug"` value must have a corresponding non-empty `<slug>/snippet.md` file
393+
- The `"articles[].name"` key is required
394+
- The `"articles[].name"` value must be a Title Case string³ with length <= 255
395+
- The `"articles[].blurb"` key is required
396+
- The `"articles[].blurb"` value must be a non-blank string¹ with length <= 350
397+
- The `"articles[].authors"` key is required
398+
- The `"articles[].authors"` value must be a non-empty array
399+
- The `"articles[].authors"` values must be non-blank strings¹
400+
- The `"articles[].authors"` values must not have duplicates
401+
- The `"articles[].authors"` values are treated case-insensitively
402+
- The `"articles[].contributors"` key is optional
403+
- The `"articles[].contributors"` value must be an array
404+
- The `"articles[].contributors"` values must be non-blank strings¹
405+
- The `"articles[].contributors"` values must not have duplicates
406+
- The `"articles[].contributors"` values are treated case-insensitively
407+
- Users can only be listed in either the `"articles[].authors"` or `"articles[].contributors"` array (no overlap)
408+
409+
### Rule: exercises/{concept|practice}/&lt;slug&gt;/.articles/&lt;article-slug&gt;/content.md is valid
410+
411+
- The file's presence is required if a matching `"articles[].slug"` entry exists in the `.articles/config.json` file
412+
- The Markdown must conform to the [Markdown standards](/docs/building/markdown/markdown)
413+
- Links must be absolute (relative links are not allowed)
414+
415+
### Rule: exercises/{concept|practice}/&lt;slug&gt;/.articles/&lt;article-slug&gt;/snippet.md is valid
416+
417+
- The file's presence is required if a matching `"articles[].slug"` entry exists in the `.articles/config.json` file
418+
- The Markdown must conform to the [Markdown standards](/docs/building/markdown/markdown)
419+
- The snippet must have at most 8 lines (leading and trailing code fence markers are ignored)
420+
325421
### Rule: exercises/shared/.docs/debug.md is valid
326422

327423
- The file's presence is optional

building/tracks/README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,13 @@ Tracks have two types of exercises:
2020
- Concept exercises: they are designed to teach one or more concepts to a student. Check the [documentation](/docs/building/tracks/concept-exercises) for more information.
2121
- Practice exercises: they are designed to practice learned concepts. Check the [documentation](/docs/building/tracks/practice-exercises) for more information.
2222

23-
Exercises can have approaches associated with them, which describe the different ways in which an exercise can be solved.
24-
Check the [documentation](/docs/building/tracks/approaches) for more information.
23+
### Dig deeper
24+
25+
Each exercise has an optional Dig Deeper section that can contain:
26+
27+
- [Approaches](/docs/building/tracks/approaches): different ways in which the exercise can be solved
28+
- [Articles](/docs/building/tracks/articles): describe interesting aspects of the exercise
29+
- Community videos: videos that showcase the exercise, usually by having someone solve the exercise from scratch
2530

2631
## Shared files
2732

building/tracks/approaches.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ An approach should explore how an exercise can be solved a certain way.
99
- Its contents should either:
1010
- Explore an idiomatic approach
1111
- Explore a non-idiomatic, but interesting approach
12-
- Contain a meta discussion (e.g. comparing the performance of approaches)
1312
- Start with a (full) code sample
1413
- Liberally use code samples in the rest of the document
1514
- Feel free to dig deep into the topic
1615
- Link to useful resources (e.g. documentation)
1716
- The snippet should showcase the core of the approach
1817
- A maximum of 8 lines can be used
1918

19+
If you'd like to compare different approaches, please write an [articles](/docs/building/tracks/articles).
20+
2021
## Approaches overview
2122

2223
- Give context to the problem

building/tracks/articles.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Articles
2+
3+
Each exercise can have articles associated with them, which explore some interesting aspect of the exercise.
4+
5+
## Topics
6+
7+
Potential topics an article could explore:
8+
9+
- Comparing the performance of different approaches
10+
- Anything interesting you can come up with!
11+
12+
## General considerations
13+
14+
- If your article is based on some code you've written, consider committing that code (within the article directory)
15+
- An example being an article on performance, for which benchmarking code was written
16+
17+
## What exercises to write articles for?
18+
19+
Any exercise, as long as there is something interesting to explore.

building/tracks/concept-exercises.md

Lines changed: 118 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ These files describe approaches for the exercise.
5656
- `.approaches/<approach-slug>/content.md`: description of the approach (optional)
5757
- `.approaches/<approach-slug>/snippet.txt`: snippet showcasing the approach (optional)
5858

59+
### Article files
60+
61+
These files describe articles for the exercise.
62+
63+
- `.articles/config.json`: metadata for the articles (optional)
64+
- `.articles/<article-slug>/content.md`: description of the article (optional)
65+
- `.articles/<article-slug>/snippet.md`: snippet showcasing the article (optional)
66+
5967
### Exercise files
6068

6169
The language-specific files, like the implementation and test files. The names of these files are track-specific.
@@ -72,11 +80,16 @@ exercises
7280
└── concept
7381
└── cars-assemble
7482
├── .approaches
75-
| ├── performance (approach)
83+
| ├── for-loop
7684
| | ├── content.md
7785
| | └── snippet.txt
7886
| ├── config.json
7987
| └── introduction.md
88+
├── .articles
89+
| ├── performance
90+
| | ├── content.md
91+
| | └── snippet.md
92+
| └── config.json
8093
├── .docs
8194
| ├── introduction.md
8295
| ├── instructions.md
@@ -403,7 +416,7 @@ If readability is your primary concern (and it usually should be), the LINQ-base
403416

404417
**Presence:** Optional (required when an approach introduction or approach exists)
405418

406-
This file contains meta information on the exercise:
419+
This file contains meta information on the exercise's approaches:
407420

408421
- `introduction`: The GitHub username(s) of the exercise approach introduction's author(s) (optional)
409422

@@ -432,6 +445,96 @@ This file contains meta information on the exercise:
432445
"approaches": [
433446
{
434447
"uuid": "448fb2b4-18ab-4e55-aa54-ad4ed6d5f7f6",
448+
"slug": "span",
449+
"title": "Use Span<T>",
450+
"blurb": "Use Span<T> to efficiently reverse a string.",
451+
"authors": ["erikschierboom"]
452+
}
453+
]
454+
}
455+
```
456+
457+
---
458+
459+
### File: `.approaches/<approach-slug>/content.md`
460+
461+
**Purpose:** Detailed description of the approach
462+
463+
**Presence:** Optional (required for approaches)
464+
465+
This file contains a detailed description of the approach.
466+
Check the [documentation](/docs/building/tracks/approaches) for more information on what should go in this file.
467+
468+
#### Example
469+
470+
````markdown
471+
# Span
472+
473+
```csharp
474+
Span<char> chars = stackalloc char[input.Length];
475+
for (var i = 0; i < input.Length; i++)
476+
{
477+
chars[input.Length - 1 - i] = input[i];
478+
}
479+
return new string(chars);
480+
```
481+
482+
This `Span<T>` approach uses a `for` loop.
483+
````
484+
485+
---
486+
487+
### File: `.approaches/<approach-slug>/snippet.txt`
488+
489+
**Purpose:** Snippet showcasing the approach
490+
491+
**Presence:** Optional (required for approaches)
492+
493+
This file contains a small snippet that showcases the approach.
494+
The snippet is shown on an exercise's dig deeper page.
495+
496+
Its number of lines must be <= 8.
497+
498+
Check the [documentation](/docs/building/tracks/approaches) for more information on what should go in this file.
499+
500+
#### Example
501+
502+
```csharp
503+
Span<char> chars = stackalloc char[input.Length];
504+
for (var i = 0; i < input.Length; i++)
505+
{
506+
chars[input.Length - 1 - i] = input[i];
507+
}
508+
return new string(chars);
509+
```
510+
511+
---
512+
513+
### File: `.article/config.json`
514+
515+
**Purpose:** Metadata for the articles
516+
517+
**Presence:** Optional (required when an article exists)
518+
519+
This file contains meta information on the exercise's articles:
520+
521+
- `articles`: An array listing the detailed articles (optional)
522+
- `uuid`: a V4 UUID that uniquely identifies the article. The UUID must be unique both within the track as well as across all tracks, and must never change
523+
- `slug`: the article's slug, which is a lowercased, kebab-case string. The slug must be unique across all article slugs within the track. Its length must be <= 255.
524+
- `title`: the article's title. Its length must be <= 255.
525+
- `blurb`: A short description of this article. Its length must be <= 350. Markdown is _not_ supported (required)
526+
- `authors`: The GitHub username(s) of the exercise article's author(s) (required)
527+
- Including reviewers if their reviews substantially change the exercise article (to the extent where it feels like "you got there together")
528+
- `contributors`: The GitHub username(s) of the exercise article's contributor(s) (optional)
529+
- Including reviewers if their reviews are meaningful/actionable/actioned.
530+
531+
#### Example
532+
533+
```json
534+
{
535+
"articles": [
536+
{
537+
"uuid": "6db71962-62d5-448b-a980-c20ae41013ed",
435538
"slug": "performance",
436539
"title": "Optimizing performance",
437540
"blurb": "Explore how to most efficiently reverse a string and what the trade-offs are.",
@@ -443,14 +546,14 @@ This file contains meta information on the exercise:
443546

444547
---
445548

446-
### File: `.approaches/<approach-slug>/content.md`
549+
### File: `.articles/<article-slug>/content.md`
447550

448551
**Purpose:** Detailed description of the approach
449552

450553
**Presence:** Optional (required for approaches)
451554

452555
This file contains a detailed description of the approach.
453-
Check the [documentation](/docs/building/tracks/approaches) for more information on what should go in this file.
556+
Check the [documentation](/docs/building/tracks/articles) for more information on what should go in this file.
454557

455558
#### Example
456559

@@ -469,26 +572,26 @@ In this document, we'll find out which approach is the most performant one.
469572

470573
---
471574

472-
### File: `.approaches/<approach-slug>/snippet.txt`
575+
### File: `.articles/<article-slug>/snippet.txt`
473576

474577
**Purpose:** Snippet showcasing the approach
475578

476-
**Presence:** Optional (required for approaches)
579+
**Presence:** Optional (required for articles)
477580

478-
This file contains a small snippet that showcases the approach.
479-
The snippet is shown on an exercise's approaches overview page.
581+
This file contains a small snippet that showcases the article.
582+
The snippet is shown on an exercise's dig deeper page.
480583

481584
Its number of lines must be <= 8.
482585

586+
Check the [documentation](/docs/building/tracks/articles) for more information on what should go in this file.
587+
483588
#### Example
484589

485-
```csharp
486-
Span<char> chars = stackalloc char[input.Length];
487-
for (var i = 0; i < input.Length; i++)
488-
{
489-
chars[input.Length - 1 - i] = input[i];
490-
}
491-
return new string(chars);
590+
```markdown
591+
| Method | Mean | Allocated |
592+
| -----: | --------: | --------: |
593+
| Linq | 29.133 ns | 80 B |
594+
| Array | 4.806 ns | - |
492595
```
493596

494597
---

0 commit comments

Comments
 (0)