Daniel Meier

Infrastructure, Linux, automation, and operational engineering

Lines of Code Tells You Where to Look, Not What to Think

The current discussion about the Linux kernel reaching another milestone measured in tens of millions of lines of code follows a familiar pattern. Some people treat the number as evidence of extraordinary engineering. Others present it as proof that Linux has become bloated, incomprehensible, or badly designed.

Both reactions give the number more meaning than it has.

Any specific total needs a qualification: it depends on the kernel revision, the counting tool, and which languages and file types are included. More importantly, the Linux source tree contains much more than the code running on a typical machine. It contains drivers for vast amounts of hardware, architecture-specific implementations, filesystems, platform support, comments, build files, generated code, tests, build scripts, documentation, and code excluded by a particular configuration. Much of it will never be built for one machine, and not everything that is built will be loaded.

The real problem is that people often confuse large codebase with bad codebase. Lines of Code can indicate rough size, provide context, or suggest that a subsystem deserves closer inspection. It cannot tell us whether the software is maintainable, well-owned, secure, testable, operable, or safe to change.

Read more

Git Worktree: A Practical Tutorial

You are halfway through a feature when another branch suddenly needs your attention. Perhaps a pull request needs reviewing, a hotfix needs testing, main has moved, or you need to compare your work with the latest upstream code.

In a single working directory, that interruption usually starts with cleanup. You stash unfinished changes, switch branches, wait for dependencies or generated files to change, do the urgent work, switch back, restore the stash, and try to remember where you were. If the changes are awkward to stash, you might create a temporary commit instead. If this happens often enough, you might clone the repository several times and accept the extra disk usage and maintenance.

None of those approaches is impossible, but all of them add friction. The real cost is context switching: your editor, build artifacts, running services, and mental model all belonged to one task, and switching the folder underneath them disrupts that context.

Git worktrees solve this cleanly. Instead of switching branches inside one folder, you switch folders.

Read more

My Famous Formula: Speed = Process + Automation

Engineers spend a remarkable amount of time arguing about tools.

Should we use Renovate or Dependabot? Kubernetes or a simpler container platform? Flux or Argo CD? Terraform or OpenTofu? Helm, Kustomize, Docker, GitHub Actions, GitLab CI, Jenkins, Backstage—the list is endless, and every tool has enthusiastic supporters and experienced critics.

Those discussions are not useless. Tools have different capabilities, constraints, costs, and failure modes. But “Is this tool good?” is rarely the most important question.

The same problem appears when teams discuss processes. Someone proposes mandatory approvals, new push rules, another release gate, a branching policy, or a change board because it sounds mature or because another company does it. A process is adopted before anyone has defined which concrete failure it should prevent.

The better questions apply equally to tools and processes: What problem are we solving? Which system behavior should change? How easy will the new flow be to follow and automate? What will happen when it fails? Who will own it? Most importantly, how will we measure whether it worked?

That is the thinking behind my famous formula:

Speed = Process + Automation

Read more

Renovate Is Not the Problem. Your Pipeline Is.

Keeping dependencies current is healthy engineering.

Old dependencies accumulate security issues, compatibility problems, unsupported APIs, and migration work. Small updates that could have been routine become large upgrade projects after a team ignores them for two years. Nobody seriously argues that letting dependencies rot forever is a good strategy.

But nobody wants developers to spend every morning manually reviewing five patch releases, three lockfile refreshes, two base-image updates, and another minor version of a linting plugin.

Renovate appears to solve that problem neatly: discover updates, open merge requests, keep the project current. In practice, a default installation without policy or reliable automation can quickly become dependency spam. Merge requests pile up, developers become annoyed, and the updates slowly rot somewhere on the roadside.

The real dealbreaker is not Renovate. It is the quality of the pipeline around it. Renovate does not create engineering discipline. It exposes whether a team already has enough discipline and automation to handle continuous change.

Read more

Why I Recommend Trunk-Based Development

Using branches as environments sounds attractive at first.

A dev branch, a test branch, a staging branch, and a prod branch feel simple, visible, and comfortable. Developers merge into dev, testers approve what reaches test, and production receives whatever is finally merged into prod. The branch names appear to show exactly where software is in the delivery process.

It looks like control.

In many organizations, however, this model does not remove complexity. It hides complexity until it returns in uglier forms: drift between environments, unclear release states, repeated cherry-picking, back-merges, forgotten hotfixes, merge conflicts at the worst possible moment, and uncertainty about what was actually tested versus what is running in production.

That is why I recommend trunk-based development as the default for modern delivery. Code should flow through one main branch. Short-lived branches may represent work in progress, but environments should represent deployment state, not separate code realities.

Read more