Staticsite redesign
These are some notes about my redesign work in staticsite 2.x.
Maping constraints and invariants
I started keeping notes of constraints and invariants, and this helped a lot in keeping bounds on the cognitive efforts of design.
I particularly liked how mapping the set of constraints added during site generation has helped breaking down processing into a series of well defined steps. Code that handles each step now has a specific task, and can rely on clear assumptions.
Declarative page metadata
I designed page metadata as declarative fields added to the Page class.
I used typed descriptors for the fields, so that metadata fields can now have logic and validation, and are self-documenting!
This
is the core of the Field
implementation.
Lean core
I tried to implement as much as possible in feature plugins, leaving to the staticsite core only what is essential to create the structure for plugins to build on.
The core provides a tree structure, an abstract Page
object that can render
to a file and resolve references to other pages, a Site
that holds settings
and controls the various loading steps, and little else.
The only type of content supported by the core is static asset files: Markdown, RestructuredText, images, taxonomies, feeds, directory indices, and so on, are all provided via feature plugins.
Feature plugins
Feature plugins work by providing functions to be called at the various loading steps, and mixins to be added to site pages.
Mixins provided by feature plugins can add new declarative metadata fields, and extend Page methods: this ends up being very clean and powerful, and plays decently well with mypy's static type checking, too!
See for example the code of the alias feature, that allows a page to declare aliases that redirect to it, useful for example when moving content around.
It has a mixin (AliasPageMixin
) that adds an aliases
field that holds a list of page paths.
During the "generate" step, when autogenerated pages can be created, the
aliases feature iterates through all pages that defined an aliases
metadata,
and generates the corresponding redirection pages.
Self-documenting code
Staticsite can list loaded features, features can list the page subclasses that they use, and pages can list metadata fields.
As a result, each feature, each type of page, and each field of each page can
generate documentation about itself: the staticsite
reference is
autogenerated in that way, mostly from Feature
, Page
, and Field
docstrings.
Understand the language, stay close to the language
Python has matured massively in the last years, and I like to stay on top of the language and standard library release notes for each release.
I like how what used to be dirty hacks have now found a clean way into the language:
- what one would implement with metaclass magic one can now mostly do with descriptors, and get language support for it, including static type checking.
- understanding the inheritance system and method resolution order allows to write type checkable mixins
- runtime-accessible docstrings help a lot with autogenerating documentation
os.scandir
andos
functions that accept directory file descriptors make filesystem exploration pleasantly fast, for an interpreted language!