# the vector — Full Content > architecture over syntax. a personal archive documenting the shift from writing code to directing intent. Generated: 2026-02-18T10:34:39.832Z Total articles: 5 --- # Why is "Mode" Missing from Your SQL Toolbox? URL: https://thevector.dev/blog/why-is-mode-missing-from-your-sql-toolbox Author: kdkunamneni (@kdkunamneni) Difficulty: beginner Reading time: 4 min Tags: SQL, PostgreSQL, Redshift, Statistics, Healthcare, Data Analysis Published: 2026-02-18T06:31:08.000Z If you've ever built a patient cohort in PostgreSQL or analyzed a clinical dataset in Amazon Redshift, you've likely hit a strange roadblock. You calculated the **Mean** with a simple `AVG()`. You found the **Median** with a percentile function. But when you tried to find the **Mode**, the most frequent value—the database went silent. For healthcare researchers, this feels like a glaring omission. In a world of blood types, diagnosis codes, and categorical data, the Mode is often the *only* statistic that actually matters. So, why is one of the "Big Three" missing from the standard SQL library? The answer isn't a mistake; it's a result of how databases are designed to think. --- ## 1. The "Tie-Breaker" Dilemma The biggest reason `MODE()` isn't a standard function is **mathematical ambiguity**. **Mean and Median** always result in a single, predictable number. **The Mode** can be "multimodal." What happens if your study has exactly 50 patients aged 30 and 50 patients aged 45? A standard SQL function is expected to return one value. If a database engine had to choose between two tied modes, it would have to make an arbitrary guess. To avoid "non-deterministic" results—where your query might return a different "winner" every time you run it—database architects historically left the logic up to the user. ## 2. Under the Hood: The "Frequency Map" Problem To understand why `MODE()` is hard for a database, we have to look at how it processes data. Calculating a **Mean** is computationally "cheap." The database just keeps a running total and a count as it reads the rows. It never needs to look back. Finding the **Mode**, however, requires building a **Frequency Map** in the background: **Memory Hog:** The database has to create a temporary "lookup table" in its RAM. **The Tally:** For every row it reads (say, 10 million rows), it must check: *"Have I seen 'Blood Type A' before? Yes? Increment its counter. No? Add it to the map."* **The Final Sort:** Once the scan is finished, it has to sort that entire map by the "Count" column to find the winner. In a massive data warehouse like **Redshift**, doing this across billions of rows can cause a massive memory spike. Engineers prioritized speed and "set-based" operations over a resource-heavy statistical function that could potentially crash a node. ## 3. The "SQL is Already a Mode Engine" Philosophy From a pure developer's perspective, a `MODE()` function feels redundant. SQL was built to group and count data—which is exactly what a mode is. Instead of a function, engineers just write a quick query: ```sql SELECT blood_type, COUNT(*) FROM patients GROUP BY blood_type ORDER BY COUNT(*) DESC LIMIT 1; ``` Because this logic is so fundamental to the language, adding a specific `MODE()` keyword was seen as unnecessary "bloat" for the core engine for decades. --- ## How to Actually Find the Mode (The Cheat Sheet) Since "one size fits all" doesn't work in SQL, here is how you solve the problem based on the tool you are using: ### The PostgreSQL Way (9.4+) Postgres eventually added "Ordered-Set Aggregates." It's a bit wordy, but it works: ```sql SELECT mode() WITHIN GROUP (ORDER BY blood_type) FROM patient_records; ``` ### The Redshift Way (The Window Function) Redshift is built for scale, so it doesn't like the Postgres syntax above. Instead, use a Window Function. This is actually better for researchers because it **shows you ties** if they exist: ```sql WITH counts AS ( SELECT blood_type, COUNT(*) as freq, RANK() OVER (ORDER BY COUNT(*) DESC) as rnk FROM patient_records GROUP BY blood_type ) SELECT blood_type FROM counts WHERE rnk = 1; ``` --- ## The Takeaway The absence of a simple `MODE()` function is a reminder that **databases are built for storage and retrieval, while statistics packages (like R or Python) are built for distribution analysis.** When your SQL query gets complicated just to find a frequent value, remember: the database isn't being difficult—it's just asking you to be specific about how you want to handle ties and memory in your data. --- # Cursor Commands vs Rules: When to Use What URL: https://thevector.dev/blog/cursor-commands-vs-rules-when-to-use-what Author: Sai Sreekar Siddula (@sreekar-ss) Difficulty: beginner Reading time: 4 min Tags: Cursor, AI, Productivity, Developer Tools Published: 2026-02-17T16:18:15.000Z If you're using Cursor as your AI-powered code editor, you've probably noticed two distinct ways to guide the AI: **commands** and **rules**. They might seem similar at first, but they serve very different purposes. Understanding the distinction will make you significantly more productive. ## What Are Commands? Commands are **one-off, inline instructions** you give to Cursor in the moment. You trigger them with `Cmd+K` (inline edit) or through the chat panel (`Cmd+L`). Think of commands as conversations. You're telling the AI what to do *right now*: - "Refactor this function to use async/await" - "Add error handling to this API call" - "Write tests for this component" Commands are **ephemeral** — they execute once and they're done. The AI doesn't remember them for the next task. ### When to use commands - **Ad-hoc edits**: You need a quick refactor, rename, or rewrite - **Exploratory work**: You're trying different approaches and want the AI to generate options - **One-time generation**: Writing a single test file, a migration script, or boilerplate - **Context-specific tasks**: The instruction only makes sense for this exact piece of code ## What Are Rules? Rules are **persistent instructions** that shape how Cursor behaves across your entire project. You define them in `.cursorrules` (project-level) or in Cursor's settings (global). Think of rules as *personality configuration*. They tell the AI who it should be: ``` You are a senior TypeScript developer. Always use functional components with hooks. Prefer named exports over default exports. Use Tailwind CSS for styling — never inline styles. Write concise comments only for non-obvious logic. ``` Rules are **always active** — every time the AI generates or edits code, it follows your rules automatically. You don't have to repeat yourself. ### When to use rules - **Coding standards**: Enforce consistent patterns across your codebase (naming conventions, file structure, import ordering) - **Tech stack preferences**: Tell the AI which libraries to use and which to avoid - **Style guide enforcement**: "Always use single quotes", "Prefer `const` over `let`" - **Architectural decisions**: "Use server components by default in Next.js", "Keep business logic out of UI components" - **Team alignment**: When multiple people use Cursor on the same repo, rules keep the AI consistent ## The Key Difference | | Commands | Rules | |---|---------|-------| | **Scope** | Single task | Entire project | | **Lifetime** | One-off | Persistent | | **Trigger** | You type it each time | Always active | | **Best for** | "Do this now" | "Always do it this way" | | **Analogy** | Asking a colleague a question | Setting team coding standards | ## Combining Them Effectively The real power comes from using both together. Here's a practical workflow: **Rules** set the baseline — your project's coding DNA: ``` Use TypeScript strict mode. Prefer Drizzle ORM over raw SQL. All API routes should validate input. Use Zod for runtime validation. ``` **Commands** handle the specifics on top of that baseline: > "Create a new API route for user registration that validates email format and checks for duplicate accounts" The AI will follow your rules (TypeScript, Drizzle, Zod validation) while executing the specific command (user registration endpoint). You get consistency *and* flexibility. ## A Rule of Thumb **If you're about to type the same instruction for the third time, it should be a rule.** That's it. If you keep telling Cursor "use functional components" or "add error handling to every API call," stop repeating yourself and put it in `.cursorrules`. Save your commands for the creative, context-specific work that changes every time. ## Conclusion Commands and rules aren't competing features — they're complementary layers. Rules handle the *how* (your standards, your style, your stack), and commands handle the *what* (the specific task at hand). Master both, and you'll spend less time correcting the AI and more time shipping code. --- # Building Type-Safe APIs with Next.js 15 and Drizzle ORM URL: https://thevector.dev/blog/building-type-safe-apis-with-nextjs Author: Sreekar Siddula (@sreekarsiddula) Difficulty: intermediate Reading time: 8 min Tags: Next.js, TypeScript, Databases Published: 2026-02-17T15:35:28.000Z # Building Type-Safe APIs with Next.js 15 and Drizzle ORM In the modern web development landscape, type safety isn't just a nice-to-have — it's essential. This guide walks you through building fully type-safe API routes using Next.js 15's App Router and Drizzle ORM. ## Why Type Safety Matters When your database schema, API handlers, and frontend components all share the same type definitions, entire categories of bugs simply vanish. No more `undefined is not a function` in production. ## Setting Up Drizzle ORM First, let's define our schema: ```typescript import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core"; export const posts = sqliteTable("posts", { id: text("id").primaryKey(), title: text("title").notNull(), content: text("content").notNull(), createdAt: integer("created_at", { mode: "timestamp" }).notNull(), }); ``` ## Creating Type-Safe API Routes With Next.js 15 App Router, we can create API routes that leverage our Drizzle types: ```typescript import { db } from "@/lib/db"; import { posts } from "@/lib/db/schema"; import { NextResponse } from "next/server"; export async function GET() { const allPosts = await db.select().from(posts); return NextResponse.json(allPosts); } ``` The beauty here is that `allPosts` is fully typed — your IDE knows exactly what fields are available. ## Runtime Validation While TypeScript gives us compile-time safety, we also need runtime validation for incoming data. Here's how to add that layer: ```typescript export async function POST(request: Request) { const body = await request.json(); if (!body.title || !body.content) { return NextResponse.json( { error: "Title and content are required" }, { status: 400 } ); } const newPost = await db.insert(posts).values({ id: crypto.randomUUID(), title: body.title, content: body.content, createdAt: new Date(), }).returning(); return NextResponse.json(newPost[0], { status: 201 }); } ``` ## Conclusion Type-safe APIs aren't just about preventing bugs — they're about developer experience. When your entire stack speaks the same type language, development becomes faster and more enjoyable. --- # Rust for JavaScript Developers: A Practical Introduction URL: https://thevector.dev/blog/rust-for-javascript-developers Author: Alex Dev (@alexdev) Difficulty: beginner Reading time: 12 min Tags: Rust, Web Dev Published: 2026-02-16T15:35:28.000Z # Rust for JavaScript Developers: A Practical Introduction If you're a JavaScript developer curious about Rust, you're in the right place. This guide maps Rust concepts to things you already know. ## Variables: `let` vs `let mut` In JavaScript, `let` creates a mutable variable. In Rust, `let` creates an **immutable** variable by default: ```rust let name = "world"; // immutable (like JS const) let mut count = 0; // mutable (like JS let) count += 1; // this works // name = "hello"; // this would NOT compile ``` ## No Null, No Undefined Rust doesn't have `null` or `undefined`. Instead, it uses `Option`: ```rust fn find_user(id: u32) -> Option { if id == 1 { Some("Alice".to_string()) } else { None } } match find_user(1) { Some(name) => println!("Found: {}", name), None => println!("User not found"), } ``` This is similar to TypeScript's strict null checks, but enforced at the language level. ## Error Handling: `Result` instead of `try/catch` ```rust use std::fs; fn read_config() -> Result { fs::read_to_string("config.toml") } fn main() { match read_config() { Ok(content) => println!("Config: {}", content), Err(e) => eprintln!("Error reading config: {}", e), } } ``` ## Ownership: The Big Concept This is where Rust diverges most from JavaScript. Every value has exactly one owner: ```rust let s1 = String::from("hello"); let s2 = s1; // s1 is MOVED to s2 // println!("{}", s1); // ERROR: s1 is no longer valid println!("{}", s2); // This works ``` Think of it like transferring a file instead of copying it. This is how Rust avoids garbage collection while preventing memory leaks. ## Conclusion Rust has a steeper learning curve than JavaScript, but the payoff is enormous: zero-cost abstractions, memory safety without GC, and incredibly reliable software. --- # Docker Compose Patterns for Local Development URL: https://thevector.dev/blog/docker-compose-for-local-development Author: Sreekar Siddula (@sreekarsiddula) Difficulty: beginner Reading time: 6 min Tags: DevOps, Web Dev Published: 2026-02-15T15:35:28.000Z # Docker Compose Patterns for Local Development Every developer has experienced it: "works on my machine." Docker Compose solves this by making your development environment reproducible. ## The Basic Pattern ```yaml version: "3.8" services: app: build: . ports: - "3000:3000" volumes: - .:/app - /app/node_modules environment: - DATABASE_URL=postgres://user:pass@db:5432/myapp depends_on: - db db: image: postgres:16-alpine environment: POSTGRES_USER: user POSTGRES_PASSWORD: pass POSTGRES_DB: myapp volumes: - pgdata:/var/lib/postgresql/data ports: - "5432:5432" volumes: pgdata: ``` ## Hot Reload with Volumes The key to a good DX is the volume mount: ```yaml volumes: - .:/app # Mount your code - /app/node_modules # But keep node_modules in the container ``` This gives you hot reload while keeping platform-specific native modules correctly compiled for the container's OS. ## Multi-Service Development For microservice architectures, compose files become your orchestration layer: ```yaml services: frontend: build: ./frontend ports: ["3000:3000"] api: build: ./api ports: ["4000:4000"] depends_on: [db, redis] worker: build: ./worker depends_on: [db, redis] db: image: postgres:16-alpine redis: image: redis:7-alpine ``` ## Health Checks Don't just use `depends_on` — add health checks: ```yaml db: image: postgres:16-alpine healthcheck: test: ["CMD-SHELL", "pg_isready -U user"] interval: 5s timeout: 5s retries: 5 app: depends_on: db: condition: service_healthy ``` ## Conclusion Docker Compose transforms local development from a setup nightmare into a single `docker compose up` command. Invest the time to get it right — your team will thank you. ---