Sebastiano Druda

← Back to writing

Essay / Software Engineering

A Good Development Workflow Removes Decisions You Shouldn’t Have to Make Twice

Scripts, publication gates and nearby documentation turn repeated project decisions into a predictable workflow that humans and coding agents can both follow.

A developer should not have to remember which of six validation commands is normally forgotten before a release. An article author should not need to rediscover whether a future publication date overrides a draft flag. These are project decisions that deserve a durable home.

For this website, the useful development workflow is mostly ordinary: predictable content files, a small set of scripts, tests for consequential boundaries and documentation beside the code. Its value is that the next change starts from those decisions instead of reconstructing them from a previous conversation.

Developer experience is often discussed through editor features and tool speed. Those matter, but a quieter improvement comes from removing repeated uncertainty. The workflow should make it easy to know what to run, what a result means and what still needs human judgment.

Give the routine path a name

In this repository, npm run verify runs formatting checks, linting, Astro checks, unit tests and the production build. The command does not make those activities equivalent. It gives a recurring local verification sequence one stable entry point.

That is useful because remembering a sequence is a different task from deciding whether its coverage is adequate. A named script removes the first burden and leaves the second visible. Browser tests and editorial-preview tests remain explicit additional commands because they exercise different environments and behaviors.

The best workflow is the one that makes the correct path boring.

A maintainer should be able to run the expected checks without learning a private ritual. When the checks fail, their names and output should identify which responsibility needs attention.

There is a limit to aggregation. A script called do-everything can hide too much if it formats files, changes remote state and publishes a release without a clear boundary. Routine validation and consequential deployment should remain distinguishable operations.

Encode publication rules once

An article in this site becomes public only when it is not a draft, is not a demo and has reached its publication time. That rule affects routes, listings, related content, RSS, sitemap and search.

If each consumer reimplemented the rule independently, every new content feature would create another opportunity for disagreement. A draft could disappear from Writing while remaining discoverable through search. A demo could leak into a feed because its example date was in the past.

The shared publication gate turns the rule into one inspectable decision. Tests exercise its boundary conditions, including future dates and timezones. The content schema handles structural requirements such as valid topics and explicit date offsets.

Global article numbering follows the same principle. It derives from all public articles in date order, with a deterministic tie-breaker. A filtered list uses those assigned numbers instead of creating its own local sequence. The implementation becomes easier to reason about because the visible meaning has one source.

Reproducibility begins before the build

A lockfile records dependency resolution, but the installation command still matters. npm’s documentation for npm ci describes a clean installation based on the lockfile, including failure when it disagrees with the package manifest. That makes it useful for the repository’s verification workflow.

It is not a promise that every build will remain possible forever. Registry access, supported runtime versions and platform requirements still exist. Record the expected runtime and keep the lockfile under review rather than treating it as a magical guarantee.

The same distinction applies to content. A build evaluates publication eligibility at its current time. Rebuilding an old revision later can include an article that was future-dated during the original build. A reproducible source checkout and a byte-identical historical artifact are different recovery goals.

A workflow becomes more useful when those limits are documented. Otherwise a maintainer may waste time investigating a difference that follows directly from an intentional time-dependent rule.

Put context where the next change happens

The README should help someone start and understand the project. More detailed content rules belong near the authoring workflow. For this publication, the editorial guide explains frontmatter, source standards, accent usage and the distinction between approved experience and hypothetical examples.

That documentation helps both people and coding agents. A request to add an article should not require repeating every established convention in the prompt. The repository can supply current rules and point to the existing schema and components.

Documentation can also create confusion if it duplicates implementation details without a maintenance plan. A list of allowed topics copied into several guides will eventually disagree with the taxonomy. It is better to identify the canonical file and explain how to use it.

Useful documentation removes a decision without creating a second source of truth.

Examples should teach the shape of valid work while the code continues to own executable constraints.

Make failure informative

A check that says “invalid content” leaves an author searching through the collection. A check that names the article and unknown topic makes the next action clear. The quality of a workflow includes the experience of correcting a mistake.

The same applies to browser tests. A regression about an article number should identify the slug and render context that disagree. A horizontal-overflow failure should record the viewport and affected page. Those details reduce the distance between detection and understanding.

Tests should protect meaningful behavior rather than freeze incidental implementation. For example, verifying that one article has the same number across Writing, Archive and Topics protects a user-facing promise. Checking the exact order of unrelated CSS declarations would add maintenance without defending that promise.

When an intended content expansion changes a previous fixed count, update the test’s model carefully. Preserve the assertion that all expected articles appear and demos stay excluded. Do not simply weaken the test until a larger collection happens to pass.

Use CI to repeat the contract independently

GitHub Actions organizes automated workflows around repository events, jobs and steps. In this project, it provides an independent environment for installing dependencies and running the release checks after a push.

That independence matters. A local success can depend on an untracked file or a stale build. CI helps expose that difference, although it still cannot replace visual review or prove that an external hosting account is configured correctly.

The deployment workflow adds a separate boundary. Generated output passes the release guard before transfer. Hosting credentials remain in GitHub Secrets, and the read-only preflight checks connection and destination access before an upload is attempted.

These are prepared workflow capabilities. Their presence in the repository is not evidence that a production transfer has succeeded. A good handoff distinguishes a passing build, a verified destination and an observed public release rather than compressing all three into “done.”

A useful check of the workflow is a clean-checkout exercise. Follow only the README, install the locked dependencies and run the documented validation path. Every unexplained local prerequisite is a candidate for documentation, automation or removal. The exercise should not require remembering which files a previous developer happened to have on their machine.

For coding agents, this also reduces unnecessary exploration. A clear command and a clear completion boundary let the agent spend more attention on the requested change. The benefit is not blind execution of a script; it is a common baseline from which a human can review what the change adds and what the checks actually establish.

Leave judgment outside the script

Some decisions should remain deliberate. A formatter can enforce layout, but it cannot decide whether an article’s argument is honest. A word-count check can catch an incomplete draft, but it cannot establish that the words are useful. An accessibility scan can identify particular violations while missing other usability problems.

The workflow should therefore state which review belongs to a person. For an editorial change, that includes reading the whole piece, checking sources, examining representative pages and confirming that examples do not imply invented experience.

For a code change, it includes deciding whether the implementation is proportionate to the requirement. Passing tests do not justify an unnecessary framework or a second data source that complicates future work.

The coding-agent discussion describes the importance of an observable completion condition. Durable scripts and documentation make that condition easier to inspect, while preserving responsibility for defining what completion should mean.

Automate the repeated procedure; keep the reason for it visible.

That is the kind of development experience I want for this site: fewer decisions made twice, clearer failures and enough explicit boundaries that the next change can be made confidently without reconstructing the project from memory.

Sources

  1. npm documentation: npm ci — checked 2026-10-11
  2. GitHub Docs: Understanding GitHub Actions — checked 2026-10-11

Topics

07 / Field note

The Best Code Is Often the Code You Can Delete

Removing a visitor counter simplified an entire operating model. A field note on maintenance cost, safe deletion and responsibilities hidden behind features.

maintainability · software architecture · 7 min