RSS Amplifier

Blog

Christian Rackerseder | Blog

Notes on web technologies, engineering tradeoffs, and front-end architecture.

echooff.devRSS feed ↗32 posts

Live Last read · last published · next check

Latest posts

Not every test double is a mock

Stubs control answers. Fakes provide working alternatives. Spies record interactions. Mocks carry expectations. The differences reveal how a test is coupled. Calling them all mocks hides important differences in test design.

Fire and forget still needs an owner

Choosing not to await a Promise does not remove responsibility for its failure. A fire-and-forget invoker gives detached work an explicit owner.

Translations belong to the user interface

Business logic should return application meaning, not localized text or translation keys. The user interface should decide how that meaning becomes words for a person.

Don't log at the leaf. Log at the root

When every layer logs the same failure, observability turns into noise. Let inner code return meaning and let the operation boundary report the outcome once.

Boring code is a feature

Clever code may impress in a pull request. Boring code keeps a system understandable, changeable and useful for years.

Time is an external dependency

Reading the current time looks harmless, but it hides infrastructure inside application logic. Making time explicit keeps behavior deterministic and tests simple.

Bugs are not backlog items

A zero bug policy is not about perfect software. It is about refusing to normalize known broken product behavior.

Clean Architecture protects the happy zone

Clean Architecture is not only about drawing onions or creating folders. It is about protecting pure application logic from the messy outside world.

Don't test what you don't control

Integration and end-to-end tests become noisy when they depend on systems a team cannot make deterministic or act on. Test feature changes at owned boundaries, and treat live dependencies as system, vendor or monitoring signals.

DevOps is a skill, not a role

DevOps should not be a ticket queue between product teams and production. It should be a skill every engineering team has enough of to own its product.

Prefer process.exitCode over process.exit() in Node.js

process.exit() looks explicit, but it can terminate a Node.js process before pending work has finished. Prefer process.exitCode and let Node.js shut down naturally.

Chrome DOM breakpoints: pause where the DOM actually changes

Chrome DOM breakpoints let you pause on the code that changes, removes or mutates a DOM node. They are useful when frontend behavior looks random but the DOM tells the truth.

Write good Git commit messages

Good Git commit messages are not bureaucracy. They make history easier to read, debug, review and revert. Write them in the imperative mood.

Application performance is a product requirement

Application performance is not something engineers can optimize in isolation. It is a product decision, a requirement and a trade-off that has to be made explicit.

Developer experience is a performance feature

Optimizing developer experience often has a bigger long-term impact than optimizing rendering benchmarks or bundle size. Faster engineers build better software.

Pattern matching in TypeScript today

JavaScript does not have pattern matching yet, but TypeScript developers can model states clearly and use ts-pattern for exhaustive pattern matching today.

Stop using barrel exports in JavaScript

Barrel exports in JavaScript reduce tree shaking effectiveness, hide dependencies and make code harder to maintain. Learn why you should avoid them.

Why you should not access browser globals directly

Direct access to window, document, navigator and globalThis couples your code to the runtime, makes side effects harder to isolate, and leads to brittle tests.

Stop adding console.log: use logpoints instead

Logpoints let you inspect runtime behavior without changing your code, polluting commits, or pausing execution.

Why Testing Library is not unit testing

Testing Library is useful, but rendering components and testing them through the DOM is integration testing, not unit testing.

Why you should not ship test IDs to production

React Testing Library works best with semantic queries like role and label. Shipping data-testid to production hides accessibility problems and turns test-only markup into an accidental contract.

Git LFS is useful, but it is not a free storage upgrade

Git LFS solves a real problem for large binary files, but it also adds workflow and operational complexity that teams should adopt intentionally.

Why git bisect is one of Git's most underrated features

git bisect helps you find the commit that introduced a regression, but large squash merges remove the history that makes it truly effective.

Why I do not use enums in TypeScript

Enums add runtime behavior, work against modern TypeScript workflows, and have simpler alternatives like string literal unions and const objects.

High coverage is not enough: mutation testing in TypeScript with Stryker

Code coverage shows what your tests execute. Mutation testing shows whether your tests fail when the code is wrong, and where Stryker fits.

Avoid truthy and falsy checks in TypeScript

Truthy and falsy checks in TypeScript hide intent and can introduce bugs. Prefer explicit checks for the values you actually care about.

Prefer Task over Promise in TypeScript

Promises hide failure in an untyped rejection path. Task from true-myth makes asynchronous success and failure explicit in TypeScript.

Avoid throwing for expected failures in TypeScript

Use Result in TypeScript for expected failures, Maybe for absence, and reserve exceptions for truly exceptional situations.

The Billion-Dollar Mistake: Avoid "null" in TypeScript

Why null still causes bugs in TypeScript - and how Maybe types make absence explicit.

Dependency injection without frameworks in TypeScript

Explicit dependencies improve clarity and testability. You do not need a framework to achieve that.

Why your unit tests feel fragile

Unit tests do not feel fragile because testing is hard. They feel fragile because our design mixes business logic and side effects.

Why I started this Blog

Why I finally decided to start writing on echooff.dev and what I want this blog to be.