aboutsummaryrefslogtreecommitdiff
path: root/doc/specs/20200601-serving-different-versions.md
blob: 9eb1bd8b76e68be6ca372dd72907067bd272a7bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# Problem

Feed reader users should be able to subscribe to the blog

# Background

As of this writing, the blog is served as HTML which is appropriate for
web browsers but maybe not for other mechanisms like feed readers.

Feed readers have different formats that they support:
  * h-feed is a microformat built into the page
  * rss and atom are XML based publishing formats
  * JSON feed is a JSON based publishing format
  * rss 3.0 is a text based pblishing format :P

Currently the blog contains a single generator function that copies
assets and generates HTML out of markdown files. This is good enough for
the current setup, but if it were to generate more it would get messy
real quick.

Given the constraints listed below, some formats are not recommended:
  * RSS 3.0 is not a good candidate at the moment as it would require
    us to parse the markdown to extract the title.
  * Atom would work, however, given the requirement for an id, title, and
    date this would require more effort than a more lenient format.
  * RSS 2.0 fits the constraints as we wouldn't need to specify anything
    for the item.
  * JSON Feed would work, however given the requirement for an id, thtis
    would require more effort than a more lenient format.

It is unclear whether the current constraints are good enough for feed
readers. If this causes issues, it's likely we will have to include date,
id or title as required in the other formats.

After reviewing the functionality of existing readers, it has been found
that an id and publication date would be needed for readers to behave
correctly. This means that ATOM and JSON Feed would be equally valid
as solutions than RSS 2.0

The current generator function depends on knowing a source for the post
being generated, and a target on where the assets will be placed.

# Hypothesis

Given we serve the blog in a feed reader friendly format, users will be able to subscribe.

# Test of Hypothesis

Given I add the blog to a feed reader service like Reeder or Feedly, I will be able to see the entries.
Given I add a new entry to the blog, the entries will be updated.

# Assumptions

* We can generate a valid feed with just the entries themselves and the existing
  blog data.
  * We can: Validated by generating an example file.
* Including just a list of items with the whole content is good enough for
  feed readers.
  * We can't: It seems like we'll require at least a guid. The old reader
    behaves correctly with just the guid. It's unclear whether feedly
    does since it has caching. Will leave grok running.
* It isn't required to link back, and we can include the whole text.
  * This is correct, however it might make sense to just link to the
    blog itself.

# Constraints

* We won't be parsing the markdown to generate feed items.
* We won't be adding any sort of frontmatter to the entries.
* The blog will remain ephemeral, and we won't introduce permalinks.
* We won't have configurable templating or options to add/remove
  output types.

# Solution Proposal

We will add a new step in the creation process to create metadata for the
post that will allow each post to be uniquely identified, as well as
having a publish date related to them.

We will split the current generator function into generators, and create
a new generator that will generate an RSS 2.0 file

# Blackbox

```
                   ╔══════════════════════╗
                   ║  When Adding a Post  ║
                   ╚══════════════════════╝
                      ┌───────────────┐          ┌───────────────┐
                      │               │          │               │
    ┌────────────────▶│ writeMetadata │─────────▶│ Metadata File │
    │                 │               │          │               │
    │                 └───────────────┘          └───────────────┘
    │
    │
    │             ╔════════════════════════╗
    │             ║ When Generating Output ║
    │             ╚════════════════════════╝
    │                 ┌─────────────────┐        ┌───────────────┐
    │                 │                 │        │               │
    │          ┌─────▶│ StaticGenerator │───────▶│ Static Assets │
    │          │      │                 │        │               │
    │          │      └─────────────────┘        └───────────────┘
┌───────┐      │      ┌───────────────┐          ┌───────────┐
│       │      │      │               │          │           │
│ Blog  │──────┼─────▶│ HTMLGenerator │─────────▶│ HTML File │
│       │      │      │               │          │           │
└───────┘      │      └───────────────┘          └───────────┘
               │      ┌──────────────┐           ┌──────────┐
               │      │              │           │          │
               └─────▶│ RSSGenerator │──────────▶│ RSS File │
                      │              │           │          │
                      └──────────────┘           └──────────┘
```

# Theory of Operation

## When Adding a Post

When the add function of the blog is triggered, it will shift the posts
as it currently does and then will generate a new unique ID and take the
current timestamp. This will be saved in a JSON file in the output
directory called "metadata.json"

## When Generating Output

When the generate function of the blog is triggered, it will iterate
over every post. For each of them it will parse the markdown content,
and the metadata, creating an object of type `tPost` and pushing it
to an array.

Next, it will iterate from a list of generator functions and call them
with the source and target directories, and an array containing the `tPost`
objects. Each generator function will do its work, throwing an exception
if they encounter an error.

When the static generator is called, it will remove the current assets
directory in the target directory, and recursively copy the assets from
the source directory.

When the HTML generator is called, it will parse an `html` template, using
the posts as the context, and will place the resulting file in the target
directory.

When the RSS generator is called, it will parse an `rss` template, using
the posts as the context, and will place the resulting file in the target
directory.

# Technical Specification

## The Post Data Structure

This spec introduces a data structure to help generate output.

```
tPost <Object>
  +html <String> // The markup of the post
  +publishedOn <Number> // The timestamp when this post was added
  +id <String> // The Unique ID for this post
```

Given that posts won't come in at a high enough rate, and that the
purpouse is only to help feed readers identify each unique piece of
content, for this version the `id` will be the same number as the
`publishedOn`.

## The Generator Interface

Every generator must implement this interface in order to work with
Blog.

* Generators MUST be a function
* Generators SHOULD read the source, destination, and posts parameters to
  write files.
* Generators MUST NOT write anything into the source directory
* Generators MUST return a promise
* Generators SHOULD NOT resolve the promise with any information, as it will
  be discarded
* Generators MUST throw exceptions if they encounter an unrecoverable error

```
IGenerator(source<String>, destination<String>, posts<Array<String>>) => Promise
```

## New Generators

### Static Generator

This generator will have the logic to move static assets around. It will
re-use the current asset logic in the `#_generate` method in Blog.

```
StaticGenerator <IGenerator>
```

### HTML Generator

This generator will have the logic to generate an HTML file. It will
re-use the current HTML logic in the `#_generate` method in Blog.

```
HTMLGenerator <IGenerator>
```

### RSS Generator

This generator will have the logic to generate an RSS file. It will
re-use the current HTML logic in the `#_generate` method in Blog,
however, instead of using the `index.html` template it will use a
`feed.xml` template that generates a valid RSS 2.0 feed document.

```
RSSGenerator <IGenerator>
```

## Modifications to existing parts of the code

The `#_generate` function will be modified so it will now parse the
post markdown, and then iterate over the generators, calling them 
so they create the appropriatet files.

## Important Metrics

Given we're only processing 3 blog posts, and this is a compile time
activity and not runtime, there are no recommended metrics in terms
of file throughput performance or runtime performance.

This should change if this would ever handle a higher volume, or would
be expected to run this process runtime.

## Furhter Improvements

It's recommended to eventually put more effort in assigning a unique ID
to each post so we can use more feed formats.

For more compatibility and future proofing, the same solution for
RSS could be used to generate other feed formats, just adding
a new generator

This same solution could be extended to serve the blog in different formats
(eg. a .txt that is easy to read in terminals)