CONCEPT 02 · FOUNDATIONS

Pure Core / Thin Shell

"Keep business logic separate from side effects."

architecturetestingdesign
Plain English

Separate your business logic from your side effects. Keep the logic — calculations, decisions, transformations — in pure functions that take inputs and return outputs with no database or network calls. Push all the I/O to the outer edge of your system. The result: you can test 90% of your code with zero mocks, zero test infrastructure.

Analogy

A chef vs. a waiter. The chef (pure core) just cooks: given ingredients, produces food. The waiter (thin shell) handles the messy outside world: taking orders, running cards, dealing with complaints. You can test the chef's recipes in a kitchen lab without any customers. The waiter's job is thin enough that you can trust it with minimal testing.

You already know this
A function that calculates a discount — no DB calls, just numbers in/outRedux reducers: (state, action) => newState — pure core state machinesSQL: the query is logic; the database engine is the shell that executes itDomain-driven design: the domain model is the pure core
Code Example
JavaScript
// THIN SHELL — handles I/O at the edge, nothing else
async function processOrder(userId, cartId, promoCode) {
  // Step 1: get data (side effect)
  const cart = await db.getCart(cartId);
  const user = await db.getUser(userId);

  // Step 2: pure core — all the business logic
  const total = calculateOrderTotal(cart.items, promoCode);
  const discount = getDiscount(user.tier, total);
  const finalTotal = total - discount;

  // Step 3: save results (side effect)
  await db.saveOrder({ userId, total: finalTotal });
  return finalTotal;
}

// PURE CORE — testable with zero infrastructure
function calculateOrderTotal(items, promoCode) {
  const subtotal = items.reduce((sum, i) => sum + i.price * i.qty, 0);
  const promo = promoCode === 'SAVE10' ? 0.10 : 0;
  return subtotal * (1 - promo);
}

function getDiscount(userTier, amount) {
  if (userTier === 'gold' && amount > 100) return amount * 0.05;
  return 0;
}

// Tests need zero mocks, zero DB setup:
assert(calculateOrderTotal([{price:50,qty:2}], 'SAVE10') === 90);
assert(getDiscount('gold', 200) === 10);
Apply when
Before writing any function: ask "does this need to touch the database/network/filesystem?" If no — keep it pure
When you find yourself writing mocks in tests: the function you're testing is probably doing too much — extract the pure logic
Complex business rules (pricing, eligibility, calculations) should always be pure — they're the most important to test
When onboarding new devs: pure core functions are self-documenting — they show what the system does, not how it talks to the world
Check Your Understanding
You're writing a function that calculates shipping cost based on weight, destination, and carrier rates. Where should this logic live?