Skip to main content

Flow-Based Development

The core philosophy of devfoundry


Introduction​

Flow-Based Development is an approach to software that prioritizes understanding how things work over memorizing how to write code.

Traditional programming education often starts with:

  1. Learn syntax (variables, loops, functions)
  2. Learn algorithms (sorting, searching)
  3. Now build something!

Flow-Based Development inverts this:

  1. Understand the problem as a flow (input → processing → output)
  2. Design the architecture (components and connections)
  3. Implement the design (write code)

This approach aligns naturally with:

  • How software actually works
  • How professional architects think
  • How LLMs can assist you most effectively

Core Principles​

1. Think in Flows, Not Procedures​

Traditional approach:

"I need to loop through an array and calculate the sum."

Flow-based approach:

"Data flows from user input → validation → calculation → display. Where does the calculation fit in this flow?"

Example: Chat App​

Procedural thinking:

let formattedMessages = [];
for (let i = 0; i < messages.length; i++) {
formattedMessages.push(formatMessage(messages[i]));
}
displayMessages(formattedMessages);

Flow-based thinking:

Then implement:

function handleNewMessage(content) {
const validated = validateMessage(content);
const formatted = formatMessage(validated);
storeMessage(formatted);
return updateDisplay(formatted);
}

Why it's better:

  • Each step is a clear, testable function
  • The flow is explicit and documentable
  • Easy to modify (add encryption step before storing)
  • Matches how you'd explain it to someone

2. Components That Collaborate​

Software is not a monolithic block of code. It's a system of collaborating components.

Mental model:

Think of components like people on a team. Each has a specific role. They communicate by passing messages.

Example: Chat App SPA (Single-Page Application)

Key insight

Components are independent but connected. Change one without breaking others.


3. Intuition Before Abstraction​

Don't introduce concepts until learners have the mental scaffolding to understand why they exist.

Traditional approach:

  • "Here's how inheritance works"
  • (Learner: "Why do I need this?")

Flow-based approach:

  • Show duplication problem: "We have three similar components with copy-pasted code"
  • Demonstrate manual solution: "We could extract common logic"
  • Introduce abstraction: "React has a pattern for this called hooks"
  • (Learner: "Oh! That solves the problem I was just facing")

Progression example in devfoundry:

  1. Stage 1 (CLI): Inline logic — no abstraction
  2. Stage 2 (Static web): Extracted functions — simple abstraction
  3. Stage 3 (SPA): React components — compositional abstraction
  4. Stage 4 (Fullstack): Client/server separation — distributed abstraction

Each stage introduces abstraction after you've felt the pain of not having it.


4. Start Simple, Add Complexity Deliberately​

Anti-pattern: Introduce all concepts at once

"This is a React app with TypeScript, Redux, React Router, styled-components, testing library, and..."

Flow-based pattern: Introduce one new concept per stage

"Stage 2 adds the DOM. That's the only new thing. Everything else stays the same."

Example progression:

StageNew ConceptWhat Stays the Same
1. CLIBasic program flowOrder logic
2. Static webDOM, eventsOrder logic
3. SPAReact, componentsOrder logic, DOM (abstracted)
4. FullstackClient/server, APIFrontend logic
5. DeploymentHosting, environment variablesApplication logic

Result: Each step feels manageable because you're only learning one new thing.


5. Visualize Everything​

If you can't draw it, you don't understand it.

Every system in devfoundry is accompanied by diagrams showing:

  • Module view: Files and structure
  • Component-connector view: Runtime flow
  • Allocation view: Where it runs

Why diagrams matter:

  • Force you to articulate structure
  • Reveal gaps in understanding
  • Enable communication with others (humans and AI)
  • Serve as design documentation

6. Architecture First, Implementation Second​

Traditional workflow:

  1. Start coding
  2. Figure out structure as you go
  3. End up with spaghetti code

Flow-based workflow:

  1. Understand the problem
  2. Design the flow (diagram it)
  3. Define components and connections
  4. Implement components (now it's straightforward)

Example: Adding a discount feature

Architecture-first approach:

  1. Understand: "10% off orders over $50"

  2. Design the flow:

  1. Define components:

    • calculateSubtotal(items)
    • applyDiscount(total, percentage)
    • calculateFinalTotal(subtotal)
  2. Implement (now each piece is small and clear):

function processOrder(items) {
const subtotal = calculateSubtotal(items);
const discount = subtotal > 50 ? applyDiscount(subtotal, 0.10) : 0;
return subtotal - discount;
}

Result: Clear code that matches the design. Easy to test, modify, and explain.


How Flow-Based Development Enables LLM Success​

Problem: Vague Prompts Lead to Generic Code​

Vague prompt

"Build a chat app"

Result: AI generates something, but it doesn't match your mental model, architecture, or constraints.

Solution: Flow-Based Prompting​

Architecture-first prompt

I'm building a chat app. Here's the flow:

  1. User types message in text input, clicks "Send"
  2. Message is validated → formatted with timestamp and sender → added to messages array
  3. Message list re-renders showing new message at bottom
  4. Message is persisted to localStorage
  5. On page load, messages are restored from localStorage

Module view:

  • App.jsx (main component, holds state)
  • MessageInput.jsx (compose form)
  • MessageList.jsx (displays messages)
  • utils/messages.js (formatting and storage logic)

Please implement MessageInput.jsx...

Result: AI generates code that fits your architecture, uses your structure, and matches your flow.


Practical Application​

Exercise: Think in Flows​

Pick a simple app (to-do list, calculator, weather app). Before writing any code:

  1. Draw the flow: User input → processing → output
  2. Identify components: What are the major pieces?
  3. Define connections: How do components communicate?
  4. Specify data flow: What data moves where?

Only after steps 1-4 should you start coding (or prompting an AI).


Flow-Based Development in Practice​

Real-World Example: Adding Authentication​

Procedural approach:

  • Jump into code: install library, copy-paste example, tweak until it works
  • Result: Works, but you don't understand the flow

Flow-based approach:

Step 1: Understand the flow

Step 2: Identify components

  • LoginForm (UI)
  • AuthService (handles API calls)
  • TokenStore (manages token storage)
  • ProtectedRoute (checks authentication)

Step 3: Define connections

  • LoginForm → AuthService (sends credentials)
  • AuthService → Server (HTTP request)
  • AuthService → TokenStore (saves token)
  • ProtectedRoute → TokenStore (checks token)

Step 4: Implement each component Now you can code (or prompt AI) for each piece independently.

Result: You understand the system. You can modify it confidently. You can explain it to others.


Flow-Based Development vs Traditional Approaches​

AspectTraditionalFlow-Based
Starting pointSyntax, loopsProblem as a flow
FocusHow to write codeHow the system works
Mental modelSequential instructionsCollaborating components
Diagram usageRare, after-the-factCentral, design-time
AbstractionIntroduced upfrontIntroduced when needed
ComplexityAll at onceOne new concept at a time
LLM collaborationVague promptsArchitecture-first prompts
Learning curveSteep cliffGradual stairs

Common Misconceptions​

Misconception 1: "Flow-based means no code"​

Reality: Flow-based development emphasizes understanding before implementing. You still write code — but with clarity.

Misconception 2: "This is only for beginners"​

Reality: Professional architects think this way. Seniors draw diagrams before big features. Juniors often jump straight to code.

Misconception 3: "It's slower to design first"​

Reality: Thoughtful design saves time debugging and refactoring. Quick hacks create technical debt.


Summary​

Flow-Based Development means:

  1. Thinking in flows (input → processing → output)
  2. Seeing software as collaborating components
  3. Building intuition before introducing abstraction
  4. Starting simple, adding complexity deliberately
  5. Visualizing with diagrams
  6. Designing architecture before writing code

Why it matters:

  • Aligns with how software actually works
  • Makes systems understandable
  • Enables effective LLM collaboration
  • Reduces cognitive load
  • Builds solid mental models

Next: See Architecture-First Thinking for how to apply this when prompting AI assistants.


Further Reading​