Organizing Code into Paragraphs
Good prose is organized into paragraphs. Each paragraph covers one idea. There's a topic sentence, supporting detail, and then a transition to the next paragraph.
Good code works the same way.
Blank Lines as Thought Separators
A blank line says: "We're moving to a new thought."
Without blank lines, code becomes a wall of text:
// BAD: Wall of code
function processCheckout(cart, user) {
if (!cart.items.length) throw new EmptyCartError();
if (!user.paymentMethod) throw new NoPaymentMethodError();
const subtotal = cart.items.reduce((sum, item) => sum + item.price * item.quantity, 0);
const shipping = calculateShipping(cart, user.address);
const tax = calculateTax(subtotal, user.address);
const total = subtotal + shipping + tax;
const payment = chargePayment(user.paymentMethod, total);
if (!payment.success) throw new PaymentFailedError(payment.error);
const order = createOrder(cart, user, payment);
await saveOrder(order);
clearCart(cart);
await sendConfirmationEmail(user.email, order);
return order;
}
With paragraph breaks:
// GOOD: Organized into paragraphs
function processCheckout(cart, user) {
// Validation
if (!cart.items.length) throw new EmptyCartError();
if (!user.paymentMethod) throw new NoPaymentMethodError();
// Calculate totals
const subtotal = cart.items.reduce((sum, item) => sum + item.price * item.quantity, 0);
const shipping = calculateShipping(cart, user.address);
const tax = calculateTax(subtotal, user.address);
const total = subtotal + shipping + tax;
// Process payment
const payment = chargePayment(user.paymentMethod, total);
if (!payment.success) throw new PaymentFailedError(payment.error);
// Create and save order
const order = createOrder(cart, user, payment);
await saveOrder(order);
clearCart(cart);
// Notify customer
await sendConfirmationEmail(user.email, order);
return order;
}
Now you can scan the structure without reading every line.
One Blank Line vs. Two
Use blank lines consistently:
- One blank line: Between paragraphs within a function
- Two blank lines: Between top-level declarations (functions, classes)
function firstFunction() {
// paragraph one
doSomething();
// paragraph two
doSomethingElse();
}
function secondFunction() {
// ...
}
class MyClass {
// ...
}
The Newspaper Metaphor
A newspaper article is organized top-to-bottom:
- Headline: Tells you the story in a few words
- Lead paragraph: Summarizes the key points
- Supporting details: Increasingly specific information
- Background: Context for those who want it
Code should work the same way.
File Organization
At the top of a file, put the important stuff:
// 1. Imports (dependencies)
import { Database } from './database';
import { Logger } from './logger';
// 2. Constants/configuration
const MAX_RETRIES = 3;
const TIMEOUT_MS = 5000;
// 3. Main exports (the "headline")
export class OrderService {
// Public methods first (the interface)
async createOrder(data) { }
async getOrder(id) { }
async cancelOrder(id) { }
// Private methods below (the implementation)
private validateOrder(data) { }
private calculateTotal(items) { }
private notifyWarehouse(order) { }
}
// 4. Helper functions at the bottom
function formatCurrency(cents) { }
function generateOrderId() { }
Readers who just want to use the class can stop at the public interface. Those who need implementation details scroll down.
Function Organization
Within functions, follow the same pattern:
async function processRefund(orderId, reason) {
// 1. Setup and validation (headline)
const order = await getOrder(orderId);
validateRefundEligibility(order);
// 2. Main logic (the story)
const refund = calculateRefund(order);
await processPayment(order.paymentMethod, -refund.amount);
// 3. Side effects (the details)
await updateOrderStatus(order, 'refunded');
await logRefund(order, refund, reason);
await notifyCustomer(order.customerEmail, refund);
// 4. Return result
return refund;
}
Variable Declarations
Declare variables close to where they're used, not all at the top:
// BAD: All declarations at top
function processData(items) {
let total = 0;
let count = 0;
let average = 0;
let filtered = [];
let sorted = [];
// ... 50 lines later, you finally use 'sorted'
sorted = filtered.sort();
}
// GOOD: Declare when needed
function processData(items) {
const filtered = items.filter(item => item.isActive);
const total = filtered.reduce((sum, item) => sum + item.value, 0);
const count = filtered.length;
const average = count > 0 ? total / count : 0;
const sorted = filtered.sort((a, b) => b.value - a.value);
return { sorted, average };
}
Conceptual Affinity
Code that shares a concept should be close together:
// BAD: Related code scattered
function validateUser(user) { }
function processPayment(payment) { }
function validateOrder(order) { }
function processRefund(refund) { }
function validatePayment(payment) { }
// GOOD: Grouped by concept
function validateUser(user) { }
function validateOrder(order) { }
function validatePayment(payment) { }
function processPayment(payment) { }
function processRefund(refund) { }
Or even better, group by feature:
// user-validation.js
export function validateUser(user) { }
export function validateUserEmail(email) { }
// payment-processing.js
export function validatePayment(payment) { }
export function processPayment(payment) { }
export function processRefund(refund) { }
The 30-Second Test
Can a developer understand what a file does in 30 seconds?
They should be able to:
- Read the filename and understand the domain
- Skim the imports and see the dependencies
- See the public API at a glance
- Understand the main flow without reading every line
If your file fails this test, reorganize it.
Key insight: Use blank lines to separate logical paragraphs. Organize files and functions like newspaper articles: important stuff first, details below. Group conceptually related code together. Make code skimmable.