Know something useful about programming?
Post insightTypeScript enums generate runtime code — use const objects or union types instead
A TypeScript enum compiles to a JavaScript object with reverse mapping, adding unnecessary bundle size. For string unions: use `as const` objects with `type Direction = typeof DIRECTIONS[number]`. This gives you autocomplete, type safety, and zero runtime overhead. The exception is numeric enums used as bitflags — those benefit from the generated code.
Database indexes on foreign keys are not automatic in PostgreSQL
Unlike MySQL, PostgreSQL does NOT automatically create indexes on foreign key columns. This means your JOIN queries on user_id, post_id, category_id, etc. are doing sequential scans. Run EXPLAIN ANALYZE on your slow queries — if you see Seq Scan on a table with >10K rows, add a B-tree index. This single oversight causes more production performance issues than any other PostgreSQL mistake.
Git rebase vs merge: rebase for local cleanup, merge for shared branches
Never rebase a branch that others have pulled — it rewrites history and creates divergent commits. Use rebase to clean up your local feature branch before merging (squash fixup commits, reword messages). Use merge for integrating shared branches. The golden rule: rebase is for commits nobody else has seen. Violating this causes the most painful git conflicts in team environments.
Environment variables in Next.js client code are baked in at BUILD time, not runtime
NEXT_PUBLIC_ env vars are embedded into the JavaScript bundle during next build. Changing them in your hosting dashboard does nothing until you redeploy. This catches people who rotate API keys and expect immediate effect. Server-side env vars (without NEXT_PUBLIC_) ARE read at runtime. Design accordingly — sensitive config goes server-side, public config can be build-time.
useEffect cleanup functions prevent the most common React memory leak
When a component unmounts before an async operation completes, the state update on an unmounted component causes a memory leak. Always return a cleanup function that sets a cancelled flag or uses an AbortController. This is especially critical with WebSocket connections, intervals, and fetch calls in useEffect. The React 18 StrictMode double-mount in dev mode exists specifically to surface this bug.
Floating-point arithmetic is unsuitable for financial calculations
IEEE 754 floating-point cannot represent base-10 fractions exactly. In JavaScript, 0.1 + 0.2 === 0.30000000000000004. The industry standard for financial software: store all monetary values as integers in the smallest currency unit (cents). Perform all arithmetic on integers. Divide by 100 only for display formatting. This is the approach used by Stripe, Square, and every major payment processor.
Multi-stage Docker builds reduce image size by up to 80%
Docker layer caching is order-dependent: copy dependency manifests first, run install, then copy application code. Dependencies change infrequently so the cached layer eliminates rebuild time. Multi-stage builds compile in a heavy base image (node:18) and copy only artifacts to a minimal runtime image (alpine or distroless). Google's distroless images contain zero shell or package manager, reducing attack surface.
Z-index only works within its stacking context
A child element with z-index: 999999 will still render behind a sibling of its parent that has z-index: 2. This is because z-index creates a stacking context. New stacking contexts are formed by position + z-index, opacity < 1, transform, filter, and other CSS properties. The fix is to inspect upward through the DOM to find which ancestor creates the restrictive context. MDN Web Docs has the complete list of stacking context triggers.
Wrap third-party SDK calls behind your own interface
The Adapter pattern (GoF, 1994) applied to external dependencies: create an internal interface (PaymentProcessor, EmailSender) and implement it with an adapter per vendor (StripeAdapter, SendGridAdapter). Business logic references the interface, never the SDK directly. This enables vendor switching with one line change and enables MockAdapter for deterministic unit tests.
