Quick Thoughts on Render Engine's Philosophy (circa May 2025)

29 May 2025 07:42

In our discord we had a wonderful question about Render Engine's Philosophy.

Reminder that Render Engine started as a way for me to learn Python on the job so there are places where this philosophy is inconsistent with how and where code lives but we're working to make it more consistent.

Here are some notes from that chat.

Core philosophy

The framework architecture is maintained with three foundational principles that guide all architectural decisions:

1. Ease of contribution

Since Render Engine is not anyone's full-time job, the codebase prioritizes simplicity and clarity to enable community contributions while minimizing maintenance overhead.

Since is was meant to be a way to learn we also hope that it can be a place where people new to contributing to open source can begin their OSS journey. We prioritize readability over micro-performance optimizations.

Where we need to improve

This also means that comments that explain the why's (not the what's) should exist.

2. Separation of concerns based on interaction points

Components are organized around where and how they interact with the system, creating clear boundaries and responsibilities. More on this later.

All of the foundational components of Render Engine live in the primary repo - render-engine/render-engine with the one exception being parsers. There is a render-engine-parser repo and that is because the parsers can be used independently from Render Engine itself (Perhaps you want an easy way to convert data from one type to HTML).

This separation of concerns is meant to keep the core lightweight and help with Extensibility. A great example is with render-engine init. With our template being in a separate repo and served via cookiecutter, this allows you to easily swap the default base template with your own, if you have your own preference in what you want in your site.

3. Extensibility

The framework is designed to be highly extensible through a plugin and theme system that allows for controlled customization.

Render-Engine uses pluggy (the same system used in tools like PyTest and django-simple-deploy). This allows for great extensibility that can be brought into projects without our involvement. We want you to be able to extend Render Engine for your needs without our interceding.

Architectural influences

Django inspiration

Render Engine draws heavily from Django in two key areas:

  • Class-Based Objects: Each generated page is treated as an object that can be modified, inspired by Django's Class-Based Views. Collections and Sites are also classes that can be modified and managed as independent objects. This means that you should (in theory) Create multiple websites with similar components and have them look similar but different based on configurations and settings
  • Component Registration: The extensibility system uses Django's approach to registering components, enabling multi-site management with controlled access to plugins, themes, and settings per site from a single configuration file. This means that your extensibility is by choice and there are no surprises that come from installed packages.

Flask philosophy

Like Flask, Render Engine tries to avoid a "batteries-included". This supports the core principles of ease of contribution and separation of concerns.

Core Components

The Render Engine architecture consists of four primary components, each with distinct responsibilities:

Parser

Responsibility: Converting data from one format to output markup language (usually HTML)

Parsers handle the transformation of content from various input formats into the final rendered output.

Page

Responsibility: Rendering a single page object

Pages represent individual content items and manage their own customization to the rendering process, including which plugins, templates, and parsers they utilize.

Collection

Responsibility: Rendering multiple page objects with shared base configuration

Collections manage groups of related pages that share common settings and rendering rules.

Site

Responsibility: Managing the overall rendering process for Pages & Collections

The Site component orchestrates the entire rendering workflow and maintains the registry of available plugins and themes with their default settings. While the Site manages what's available, individual Pages and Collections determine what they actually use.

Design Principles in Practice

Component Autonomy

Pages and Collections have autonomy in choosing:

  • Which plugins to use
  • Which templates to apply
  • Which parsers to employ
  • Individual settings for parsers and plugins

This autonomy operates within the framework provided by the Site's available resources.

This modular, principle-driven approach ensures Render Engine remains both accessible to contributors and powerful enough for complex static site generation needs.