All articles

The Development Setup That Stays Out of Your Way

The best tools are the ones you stop noticing. Here is how I configure my environment so that friction is tool friction, not my own.

I have a rule about development tools: a tool earns its place if it removes friction faster than its configuration costs. Most do not survive that evaluation.

Editor: VS Code with a short extension list

  • ESLint and Prettier — the linter and formatter.
  • GitLens — blame annotations and history browsing inline in the file.
  • Error Lens — inline error messages on the line where they occur instead of in a panel.
  • Tailwind CSS IntelliSense — class completion and hover documentation.
  • REST Client — send HTTP requests from a .http file and keep them in version control.

Prettier as a non-negotiation

Formatting debates are expensive — not because people care deeply but because they recur endlessly without a forcing function.

Prettier as the formatter, enforced by a pre-commit hook, removes the conversation permanently. The output is consistent. Consistency is worth more than preference.

{ "semi": false, "singleQuote": true, "trailingComma": "all", "printWidth": 100 }

ESLint for what Prettier cannot do

Prettier handles formatting. ESLint handles code quality: unused variables, missing dependencies in useEffect hooks, imports from the wrong module. The two tools have different jobs.

Git hooks via simple-git-hooks

  • pre-commit: prettier --check and eslint on staged files via lint-staged.
  • commit-msg: a script that validates the commit message format.

The pre-commit hook catches format drift before it enters the repository. The commit-msg hook means the git log is readable without a cleanup pass.

Terminal tools that actually get used

  • zoxide — directory jumping based on history. Type z proj and land in the project directory.
  • fzf — fuzzy finder for history search (Ctrl+R) and file selection.
  • bat — cat with syntax highlighting. Useful for quick file inspection without opening an editor.
  • ripgrep — faster grep with sensible defaults for searching across a project.

Docker for third-party dependencies only

I do not run the application itself in Docker during development. The hot reload latency is too slow for a tight feedback loop.

Docker handles Postgres, Redis, and any other infrastructure that would otherwise require manual installation. A docker-compose.yml in the repository root means every developer gets the same database version on first checkout.

Services I write run natively. Services I depend on run in containers. This combination gives a fast development loop without sacrificing environment consistency.