Every few years a team invents a new way to store sessions in localStorage, roll their own JWT crypto, or hash passwords with SHA-256 because “we don’t need bcrypt for an internal tool.” Then the internal tool is on the internet, or the JWT is signed with none, or XSS steals the tokens. Authentication is […]
TypeScript Types That Earn Their Keep
TypeScript is not a personality and it is not a substitute for tests. It is a way to make illegal states harder to represent and to make refactors cheaper. Teams get this wrong in two directions: any everywhere, or types so clever that nobody can add a field without a ceremony. Types earn their keep […]
Logging That Helps at 2am Instead of Drowning You
At 2 a.m. you do not want a novel. You want to know which request failed, which user, which action, and whether it is the database, the payment provider, or your null check. What you have is 40 million lines of debug from a health check, no request id, and a console.log(user) that once printed […]
How to Debug Production When You Can’t Reproduce It Locally
It happens on one customer’s account, or only after 11 p.m., or only on iOS Safari, or only when the cart has a coupon from 2019. You cannot reproduce it on your machine. Staging is green. You are tempted to add more logs everywhere and deploy. That can work. It can also fill the disk […]
Docker Compose for Developers Who Needed It Yesterday
You cloned the repo. The README says docker compose up. You have never liked Docker. Postgres fails because the port is taken. The API cannot see the database because you used localhost inside the container. The volume ate a stale node_modules. You consider installing everything on the host and pretending the README is optional. Compose […]
Error Handling That Doesn’t Leave Users Stuck
The button spins. Then it stops. Nothing happens. The user clicks again. Now they have two orders, or none, and a support ticket that says “your site is broken.” The code did handle the error. It console.error’d. It returned null. It swallowed a promise. From the system’s point of view, the error was handled. From […]
SQL Indexes for People Who Only Open Postgres When It Is Slow
The page is slow. Someone says “add an index.” You add an index on users.email because that column is in the query. The page is still slow. The query was filtering on status and sorting on created_at, and the new index is never used. EXPLAIN would have said so in ten seconds. Nobody ran EXPLAIN […]
How to Design REST APIs Frontend Teams Don’t Hate
Frontend developers do not hate REST. They hate guessing. They hate a list endpoint that returns a different shape than the detail endpoint. They hate 201 with an empty body when they need the id. They hate errors that are HTML on Tuesday and JSON on Wednesday. They hate pagination that uses page on one […]
Stop Copying useEffect Patterns That Fight React
useEffect is the hook people reach for when they do not know where the code belongs. Data fetch, syncing to a document title, resetting state when a prop changes, subscribing to a socket, transforming data that could have been a variable. The dependency array turns orange in the linter. You copy a Stack Overflow snippet, […]
How to Write a Pull Request That Gets Reviewed
A pull request sits for two days. Then someone leaves “nits” on naming and disappears. Or they approve without reading because the diff is 1,800 lines and standup is in four minutes. You did not fail at GitHub. You failed to make the review possible. Reviewers are not lazy by default. They are optimizing for […]