Skip to main content

Article

de facto standards

πŸ’‘ There are many β€œde facto standards” in software development that nobody officially mandated

One thing I find interesting about software engineering is how many conventions become standards simply because enough developers, tools, frameworks and platforms converge around them.

Some examples:

πŸ“Œ Semantic Versioning β€” MAJOR.MINOR.PATCH

2.4.1

  • MAJOR β†’ breaking changes
  • MINOR β†’ backwards-compatible features
  • PATCH β†’ backwards-compatible fixes

A version number becomes information, not just a label.

πŸ“ Conventional Commits

feat: add user authentication
fix(api): handle empty responses
refactor: simplify cache service

A predictable Git history makes commits easier to understand β€” and also enables automated changelogs and releases.

πŸ“„ README.md

There is no law saying a repository needs a README.md.

Yet when we open an unfamiliar repository, it is usually the first file we look for.

What is this project?
How do I install it?
How do I run it?

That convention is so strong that GitHub, GitLab and other tools treat it specially.

πŸ”’ .gitignore

Another tiny file that became practically universal.

node_modules/
vendor/
.env
IDE metadata
build artifacts
cache directories

It establishes the boundary between source code and local/generated state.

βš™οΈ .env + .env.example

Environment-specific configuration should not normally live directly in source code.

A common pattern became:

.env β†’ local/private values
.env.example β†’ documented configuration contract

This idea appears across PHP, Node.js, Python and many other ecosystems.

πŸ” Secrets don't belong in Git

API keys, production passwords and credentials are expected to come from environment variables, secret stores or deployment infrastructure.

The interesting part is that this convention is now understood not only by developers, but also by CI systems, cloud platforms and security scanners.

πŸ“¦ Dependency lock files belong in the repository

composer.lock
package-lock.json
pnpm-lock.yaml
Cargo.lock

The dependency manifest says what versions may be installed.

The lock file records what versions were resolved.

That distinction is fundamental for reproducible builds.

🌿 Pull/Merge Requests instead of pushing directly to main

Branches + review + CI + merge.

Git itself does not require this workflow.

But GitHub, GitLab and modern engineering teams have effectively built an entire collaboration model around it.

Protected branches reinforce the convention.

πŸ€– CI runs before merge

A modern repository increasingly assumes that every change will automatically trigger:

  • tests
  • linting
  • static analysis
  • build checks
  • security scanning

β€œWorks on my machine” gradually became less acceptable because the repository itself can verify the change.

🎨 Automated formatting

Prettier, gofmt, Black, PHP-CS-Fixer…

Instead of spending code-review time discussing whitespace and formatting, teams let deterministic tools decide.

In some ecosystems, formatting has effectively stopped being a matter of personal style.

🌐 JSON + HTTP for APIs

A typical API today often looks unsurprising:

GET /users/42

200 OK

{  "id": 42,  "name": "Alice" }

HTTP verbs, HTTP status codes and JSON became a shared vocabulary between systems written in completely different languages.

πŸ“‘ OpenAPI for describing HTTP APIs

Once APIs became central to software architecture, we needed a machine-readable contract.

OpenAPI increasingly fills that role:

API β†’ specification β†’ documentation β†’ client generation β†’ validation β†’ testing.

πŸ•’ ISO 8601 timestamps

2026-08-07T16:30:00-05:00

Dates are surprisingly difficult in distributed systems.

Using an unambiguous representation β€” and often storing timestamps internally in UTC β€” has become one of those conventions developers learn after enough painful timezone bugs.

πŸ”€ UTF-8

Encoding used to be something developers had to think about constantly.

Today, UTF-8 is so dominant that many systems simply assume it.

That is perhaps one of the best examples of a successful de facto standard.

πŸ₯ Health endpoints

/health
/status
/ready

Once applications started running behind orchestrators, load balancers and monitoring systems, exposing machine-readable health became a common architectural convention.

πŸ“Š Structured logging

Instead of:

Something went wrong

modern systems increasingly emit structured context:

{  "level": "error",  "request_id": "abc123",  "service": "payments",  "message": "Payment provider unavailable" }

Logs stop being text files and become queryable data.

πŸ”— Correlation / Request IDs

One HTTP request may cross five services.

Giving that request an identifier that travels through the system makes distributed debugging dramatically easier.

Another convention that emerged naturally as architectures became more distributed.

πŸ—οΈ Architecture Decision Records (ADRs)

Code tells you what the system does.

It rarely tells you why an architectural decision was made.

Small Markdown records such as:

ADR-004: Use PostgreSQL instead of MongoDB

preserve that context for the next developer β€” or for yourself six months later.

πŸ“š Documentation as Markdown inside the repository

README.md
docs/architecture.md
CONTRIBUTING.md
CHANGELOG.md

Documentation living next to the code can be versioned, reviewed and changed together with the implementation.

πŸ“‚ Recognizable project structure

src/
tests/
docs/
config/

There is no universal directory structure.

Still, conventions matter because a developer opening an unfamiliar project can often understand its basic organization in seconds.

πŸš€ Infrastructure as Code

Servers and infrastructure increasingly stopped being something somebody manually configured.

Terraform, Ansible, Kubernetes manifests and similar approaches made infrastructure something we can:

version β†’ review β†’ test β†’ reproduce.

And there are many more:

βœ… automated tests
βœ… static analysis
βœ… dependency injection
βœ… SOLID
βœ… staging environments
βœ… code reviews
βœ… changelogs
βœ… feature branches
βœ… dependency-update bots
βœ… security scanning
βœ… HTTPS everywhere
βœ… pagination for APIs
βœ… idempotent operations
βœ… Dockerfiles
βœ… CI/CD pipelines

None of these are universal laws.

Some are formal specifications.
Some are conventions.
Some are architectural patterns.
Some are simply habits that became incredibly widespread.

But together they form something important:

a shared vocabulary for building software.

And I suspect these conventions will become even more valuable with AI coding agents.

An agent entering a repository with conventional commits, ADRs, predictable directories, tests, OpenAPI definitions and documented configuration has dramatically more context than an agent entering an unstructured codebase.

Maybe good conventions were never just about making software easier for other developers to understand.

Now they also make software easier for machines to understand. πŸ€–

What other β€œde facto standards” would you add?