# Reactionary programming principles

These principles decide how reactionary code is written. They are rewritten here from Franklin's page "Reactionary Programming Principles" (`principles.html` on www.reactionary.software, source `src/principles.html.luan` in the `reactionary` repository), with decisions from real code that show each one applied. Ousterhout's paper "Scripting: Higher Level Programming for the 21st Century" (1998) is part of these principles; the luan website has a copy at `website/src/scripting.html.luan`.

They are principles, not rules. When two conflict, there is no formula. Look at how similar decisions went, and use judgment.

"Reactionary" doesn't mean that old is better. Most programming before about 2000 was good and most since is bad, but some old things are bad and a few new things are good. Choose what is best by these principles, whatever its age. Java, garbage collection and JIT compilation are good; using C for everything is not.

Without these principles you will write modern code, because that is what most of the code you learned from is like. Modern programming values the opposite of what follows.

## First principles

These three come from the Old Testament. Everything else follows from them.

### Emet: reliability over the long term

Code must have no bugs and no unpredictable behavior now, and must stay easy to maintain and adapt for years.

### Be fruitful: make things easier

Being productive means making work easier, which often takes some invention. Code that takes a struggle to write, debug or change is bad code. When code gets hard, stop and ask what would make it easy, instead of adding more code.

### Empiricism: judge ideas by how they work in practice

- Judge an idea by its results over time. When adding a new idea, note what it is, when it was added, and what it should achieve. Later, note what it actually did. If it doesn't prove its worth, remove it. Franklin removes most of the ideas he tries.
- Take new ideas from real experience, above all from difficulties in working with code. Never take them from what is popular with modern programmers.
- Arguing from evidence works; arguing from theory doesn't. A failure you actually produced (an injection URL that you ran and that ran a script) is convincing. A risk you can only describe usually isn't, and a problem that has never happened in practice may not be worth fixing: Luan accepts an extra `nil` argument, which would ideally be an error, but it has never caused trouble, so nobody spends time on it.
- Luan's design came from experience. Conditions must be booleans, and extra arguments are errors, because both caused real debugging problems. Concatenation converts `nil` to a string, because logging statements concatenate and must never fail, and `nil` in concatenation has never caused a problem.

## Derived principles

### Simplicity

Simple means easy to understand. It does not mean minimal.

- Code that makes code easier to understand is good, even when it adds lines: `{nil}` to show that a table is meant as a list, `end_if` and `end_function` to show which block ends in long nested code, CSS padding written out in full (`padding-top`, `padding-left`) rather than a shorthand whose order must be remembered.
- Code that makes no sense must be removed. It costs the computer nothing, but every reader has to work out that it means nothing. Dead code, unused parameters, commented-out lines and leftover debug lines are never "harmless". The exception is standard boilerplate that a reader recognizes at a glance, such as `local error = Luan.error` or an unused `logger` at the top of a Luan file.
- Readability comes before performance, unless performance actually matters.
- At the small scale, simplicity is plain, readable code. At the large scale, it is a few simple ideas used consistently.
- Simple code is hard to write. Think about the problem until you see its essence, then write that plainly. goodjava's parser came from this: a stack of positions in effectively recursive descent, which makes parsing JSON, HTTP, CSS and Luan itself simple. Good code makes the problem look like nothing special.
- Simple languages make simple code. Avoid languages with several paradigms. Luan is a deliberately simple language for applications.

### Make things explicit

Hidden behavior is magic, and magic is hard to understand.

- Every import is explicit. In Luan, `local head = Shared.head or error()` shows where `head` comes from, keeps calls short (`head()`, not `Shared.head()`), and fails at load time if the name is wrong.
- Callbacks are explicit. In JavaScript, don't use `async`/`await` or promise chains: they hide the callbacks. An `async` function returns at its first `await`, other code can run at every `await`, and a `throw` becomes a rejected promise that `window.onerror` never sees. Use `XMLHttpRequest` with an explicit `onload`, not `fetch`.
- In user interfaces, no hidden modes: state the user must know about is visible, and chosen by the user.
- Prefer checks that need no stored state. A drag-and-drop library tests `event.isPrimary` instead of storing a `pointerId`.

### Make debugging easy

Bugs should be found quickly and fixed easily.

- Fail fast, as close to the cause as possible: compile errors for undefined names, boolean-only conditions, errors for extra arguments, and `x or error()` throughout the code.
- Log errors well. Reactionary sites with nontrivial JavaScript send every browser error to `/error_log.js`, so it reaches the server log.
- Anything that makes a failure silent or hard to trace is a serious problem, even if it looks small.
- Simplicity is also security. Log4j had disastrous security holes because a logger evaluated expressions; a logger should just log strings.

### Handle the needed cases simply, in a way that generalizes

Don't implement what isn't needed yet, but write the current code so that adding it later is possible. Luan has no bitwise operators until someone needs them. goodjava's webserver does only what its sites use. Cheap protection against future change is good: Luan library modules in a site require each other inside the functions that use them, so a new circular dependency never forces a change.

### Use thin layers

Code that gives access to a protocol or to some core function should be a thin layer over it. goodjava's webserver passes plain `Request` and `Response` structs that hold the actual HTTP data, with no getters, setters or servlets. `goodjava.mail` lets the caller set the MIME headers directly; to send a complicated email, look at the source of one you received and copy its headers. A thick layer that thinks it knows better than the protocol hides what is happening and makes debugging harder.

### Modularity, at the right scale

A module is a library, exposed through its API, or an application, exposed through its UI and perhaps a protocol. A class is too small to be a module; treating classes as modules adds more complexity than it saves. Each module does one thing well.

Ousterhout's idea is the logical end of this: write libraries in a system language and applications in a scripting language. Luan is the scripting language and Java the system language. Use Java for components with complex algorithms or data structures, and Luan to put components together into an application. A complicated application may still need complicated Luan.

### Fix a problem once, at its root

Don't patch the same problem in many places when it can be fixed once at its root. Patches get missed, and the root stays broken. When the problem is in a library, fix the library rather than working around it in applications.

- A URL path containing `..` is a security hole, so goodjava's webserver rejects such paths for every site, instead of each handler checking.
- `Math.random` is to be made secure inside Luan, instead of each application using a secure generator.
- A request from another site that changes data is also a security hole, but the library can't know which requests change data, so the Referer check belongs in the application. Whether one place in the application can cover every case depends on the application. Chat does it once, in `User.current()`, for every path ending in `.js`, because every change in chat goes through a `.js` handler.

### Judge conventions by their design, not their popularity

Prefer your own simple solution to a standard that is badly designed. Examples from reactionary code:

- Forged requests are stopped by checking the Referer header, not with `SameSite` cookies plus POST-only handlers, whose rules are complicated enough that even careful programmers get them wrong.
- HTML is styled with attributes, `<div content>`, not classes.
- `div` and `span` instead of the newer semantic tags, whose idea of semantics doesn't hold up in practice.
- `title` on clickable icons rather than `alt`, because `title` is visible to everyone.
- Mercurial, not Git. Java 8, not later versions, which got worse. Software maintained by modern programmers usually gets worse with each version, so don't upgrade by default; but do upgrade when the new version is actually better.

When reviewing such a choice, judge whether it works, and say precisely where it is weak, if it is. Imprecise reasoning will be rejected, and should be.

### Avoid code that must be puzzled over

Don't write code a reader would have to puzzle over, even for the sake of safety, unless it is hidden inside a library. Making chat's generated passwords unpredictable by calling a secure random generator in chat was rejected; making Luan's own `Math.random` secure was accepted.

## Consistency

Franklin lets small irregularities happen in his own code, as a craftsman who is still improving his style. That is for him, not for you. Follow the current practice of the reference projects consistently, and don't copy irregularities you find in older code.

## The Old Testament guide to programming

Franklin's paraphrase:

> Do not follow most programmers in writing bad code. -- Exodus 23:2
>
> Do not make an ideology for yourself. You must not bow down to ideologies or serve them. -- Exodus 20:4-5
>
> You must not mix two different coding conventions, create programming languages with two programming paradigms, or write code made of two styles. -- Leviticus 19:19
>
> Do not write magic code and do not write code that requires divination to understand. -- Leviticus 19:26
>
> You must purge the bad (programmers and code) from you. -- Deuteronomy many places
>
> Woe to those who call bad code good and good code bad, who substitute complexity for simplicity, who substitute compactness for readability. Woe to those who are wise in their own opinion and clever in their own sight. -- Isaiah 5:20-21
>
> Hate bad code and love good code; and establish judgement in the project. -- Amos 5:15
>
> Though I walk through the Silicon Valley of darkness, I will fear no evil. -- Psalm 23:4
