project outline devlog post (#19)

* initial dump for project outline post

* complete first draft of the post

* draft change of plans post

* cleanup project outline

* grammar fixes
This commit is contained in:
Facundo Olano 2024-02-29 13:29:49 -03:00 committed by GitHub
parent 240aa38d3d
commit 17c6c46eab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 193 additions and 2 deletions

View file

@ -0,0 +1,48 @@
---
title: A change of plans
date: 2024-03-02
layout: post
lang: en
tags: [project, emacs]
draft: true
---
#+OPTIONS: toc:nil num:nil
#+LANGUAGE: en
Up until I started coding ---while I was [[file:getting-started-with-go-and-emacs][setting up my environment]] and going through a couple Go tutorials--- I captured the concept I had for the project in a couple of slogans:
- golb is a small, opinionated static site generator written in Go and inspired by Jekyll.
- The golb blog is a blog about learning go by implementing a blog generator.
There were some problems with this project idea:
1. The ~golb~ name stank.
#+ATTR_HTML: :type a
a. Apart from stinking, this name choice showed that the project was rather generic: its remarkable features were that it would be written in Go (an implementation detail) and that it would have some facilities for blogging (as was the case for every other static site generator).
2. It was actually two projects in one: a site generator and a development blog.
#+ATTR_HTML: :type a
a. Previous experience has showed me that trying to keep a devlog while I work on a project distracts me from the actual work on the project.
/Wait/, you may ask, /isn't this the devlog of the project?/ It is, but I cheated: I'm writing this retrospectively, based on a few notes I took during development <and offloading ideas I've been carrying for days>, after finishing most of the work I planned for the project.
I love writing as much as software building, and because of that I'm always inclined to write about what I build, but writing is as absorbing and demanding as programming is to me; if I attempt both in parallel, the writing suffers and the programming suffers.
Not only it takes time and mental real estate away from the programming; writing as I build feels off to me for the same reasons why I don't like to introduce abstractions or factor the code early on, or why test-driven development isn't appealing to me: they make me focus and get attached to particular solutions before being confident enough that they will work, even before understanding the problem I'm trying to solve.
-----
The problems went away when I found out that exporting org-mode files to HTML was feasible in go. I had thrown in /org-mode support/ as a "nice to have" feature in my preliminary plan, not knowing what kind of work that would entail. But some googling revealed that Hugo already supported org-mode posts, relying on an [[https://github.com/niklasfasching/go-org][external library]] that I could use myself.
Adding first-class support for org-mode syntax for blog posts made a lot of sense:
- It would make the project feel less "generic". This was confirmed by a name change, first to ~blorg~, which I dropped because it was used elsewhere, then to ~jorge~, which also had /org/ in the name, sounded like it could be Hugo's distant cousin, and paid homage to two of my [[https://en.wikipedia.org/wiki/Jorge_Luis_Borges][favorite]] [[https://en.wikipedia.org/wiki/Jorge_Garcia][artists]].
- It would it make useful to me, more rather than just an learning project, since I blog by writing org-mode files and, in fact, that was the source of the few rough edges of my current Jekyll workflow[fn:1]. My static site generator would implement my exact blogging workflow out of the box.
- I could use my current Jekyll blog as a reference and as test input, planning to "dogfood" by ultimately migrating it to ~jorge~. This would, in turn, remove the need to write a devlog to test the site generator.
This change immediately made the project more interesting, because I was producing a tool that I was interested in using myself and, if I succeeded, maybe someone else could find it useful too. There already were plenty of ways to blog with org-mode, and I imagine most org-mode hackers would prefer to write some emacs-lisp to install an external program, but there may be some value in a tool that:
1. Allows you to start an org-mode-centric blog with a single command.
2. Allows you to add org-mode support to a pre-existing jekyll blog without much effort.
*** Notes
[fn:1] Namely: it required me some extra project setup to instruct emacs how to export my org files; since the default org to HTML export produced an awkward HTML structure, I was using org to markdown and letting Jekyll turn markdown to HTML; I had to manually export files before they were picked up by the ~jekyll serve~ live reload feature; renaming, changing dates and moving out of draft required changing both the .org and the .md source files.

View file

@ -0,0 +1,143 @@
---
title: Project outline
date: 2024-02-29
layout: post
lang: en
tags: [project]
---
#+OPTIONS: toc:nil num:nil
#+LANGUAGE: en
** User interface
When I'm toying with the idea for a new project, I start by picturing what it could look like from the perspective of the users: what the interface will be. For web applications, this means deciding what actions will I make available to them, what menus and buttons, and what information I need to display on a given view. Then I make some sketches to figure out how to fit all that into a web page layout[fn:1]. For command-line applications it gets much easier: I just need to come up with the right list of program subcommands, some of its flags, and a couple of usage examples.
As soon as I [[file:why][decided to work on a static site generator]], I narrowed the commands I needed to support down to four: ~init~, ~build~, ~serve~, and ~new~. Below are some transcripts of my notebook, showing how I first imagined these commands would work (at this point I was calling the program ~golb~):
#+begin_src
$ golb init
$ golb init +now -rss -tags
$ golb init +now +rss +tags
$ golb init empty
$ golb init index
$ golb init blog
#+end_src
~init~ would be in charge of creating a new project with default files. I wanted this command to optionally "scaffold" a fully-featured website. The first way I pictured that was with an extensible flag system (~+rss~ turns the RSS feed on, ~-tags~ disables the tag list page, etc.); I later considered using site profiles for that purpose (a standalone ~index~, a full ~blog~, etc.). But, eventually, I realized that both of those options would just confuse the user and over-complicate the implementation. So ~init~ was left without flags, always creating the same default site; if users wanted an empty project they could just omit the ~init~ command altogether.
#+begin_src
$ golb serve [--drafts] [--future] [--no-reload]
$ golb build [--minify]
#+end_src
The ~serve~ command would run a local file server for previewing the site, while ~build~ would prepare the files for production. I wrote down some flags to help me picture what other features those commands could support (minifying the output, live reloading the browser upon file changes, etc.). I ended up implementing most of those features but opted for reasonable defaults over command-line flags to narrow the interface.
#+begin_src
$ golb new
> title:
> tags:
$ golb new post
$ golb new note
#+end_src
The ~new~ command would be a helper to create blog posts with some of the boilerplate (e.g. the front matter) already filled in. I eventually renamed this subcommand to ~post~ and dropped most of its options.
** Project plan
Based on that CLI outline, I gave some thought to each of the subcommands and flags I planned to implement, trying to imagine, at a high level, which operations they should consist of, what parts seemed easy or complicated to program, which ones I wasn't yet sure how I could tackle, what work I expected to delegate to third-party libraries, and where I suspected the "unknown-unknowns" of the project could be lurking. This exercise yielded a preliminary list of tasks, that I added to my project board:
#+begin_src
** Tasks
1. setup go and emacs
2. hello world
3. first stab at golb init
4. dummy golb build command
5. deploy to server
6. accept markdown as input
7. treat input files as templates
8. add some sort of layouts or template inheritance
9. parse input front matter
10. golb new to add a new blog post
11. tags
12. generate rss with build
13. --draft and --future support
14. some way of opting in and out of features on golb init
15. golb serve
16. post pagination
17. golb serve watch/autorefresh
** Nice to haves
1. minify output html and css
2. yaml data files
3. org-mode support
4. permalink override
5. add features after first initialization
6. optional per-tag rss feed
#+end_src
Some things to note from this list:
- This wasn't a strict plan I expected to follow but rather a list of work I had already identified, a guide to see where I needed to do more thinking, and another chance to validate my assumptions about the scope of the project.
- The order of the tasks was influenced by the user journey I imagined (e.g. first run ~golb init~), but as soon as I started working on the project I realized I should prioritize first the "mission critical" commands (~golb build~), then the most complex to implement (~golb serve~), regardless of the user flow.
- I captured some "nice to have" tasks that sounded interesting or fun to implement but were not required for the project to make sense or that I didn't know how feasible they were. One such case was the org-mode support; as I'll explain later, learning that there already was a Go library to parse org-mode syntax would lead me to redefine the goals of the project.
** Some code
One nice quality of command-line programs is that the user interface tends to easily translate into the top layer of the program, each subcommand offering a good starting point for the coding. Looking at the ~main.go~ file from [[https://github.com/facundoolano/jorge/commit/16cbf1d10ea890df216b74ad9231a1b70ad102c3#diff-2873f79a86c0d8b3335cd7731b0ecf7dd4301eb19a82ef7a1cba7589b5252261][an early commit]] shows much of the initial project plan already stubbed in the code:
#+begin_src go
package main
import (
"fmt"
"os"
)
func main() {
if len(os.Args) < 2 {
printAndExit()
}
switch os.Args[1] {
case "init":
// get working directory
// default to .
// if not exist, create directory
// copy over default files
fmt.Println("not implemented yet")
case "build":
// delete target if exist
// create target dir
// walk through files in src dir
// copy them over to target
// (later render templates and org)
// (later minify)
fmt.Println("not implemented yet")
case "new":
// prompt for title
// slugify
// fail if file already exist
// create a new .org file with the slug
// add front matter and org options
fmt.Println("not implemented yet")
case "serve":
// build
// serve target with file server
// (later watch and live reload)
fmt.Println("not implemented yet")
default:
printAndExit()
}
}
func printAndExit() {
// TODO print usage
fmt.Println("expected a subcommand")
os.Exit(1)
}
#+end_src
** Notes
[fn:1] And then hitting a bunch of walls trying to make that happen with CSS.

View file

@ -43,7 +43,7 @@ What else, then? Other than servers, Go is known to be good at command-line appl
I read somewhere that a blog is the ideal learning project for software developers: it can get as simple or as complex as you want, it exposes you to the entire web stack, from server setup to UI design, and when it's working you are encouraged to write about something (most likely about setting up a blog).
That notion, projected into the CLI application space, yields a static site generator: a command-line tool to set up blogs. For a number of reasons, this seemed like the kind of project I was looking for:
That notion, projected into the CLI application space, yields a static site generator: a command-line tool to set up blogs. For several reasons, this seemed like the kind of project I was looking for:
- I knew static site generators were useful because I'd been using one (Jekyll) for years.
- Moreover, since I had recently rewritten my blog from scratch, I knew what I'd like to reproduce and what to change from Jekyll, and I knew that, at least on a first look, it was about the project size I was looking for: not so small as to be boring, not so big as to get out of hand.

View file

@ -51,7 +51,7 @@ $ jorge serve
<h2><a href="/blog" class="title" id="devlog">Devlog</a></h2>
{% for post in site.posts | reverse limit:5 %}
{% for post in site.posts | reverse %}
{% include post_preview.html %}
{% endfor %}