Navigation Patterns & Component Classification
Learn how to navigate codebases efficiently and classify components correctly.
Learning Objectives
By the end of this module, you will be able to:
- Navigate codebases efficiently using established patterns
- Classify components correctly (Zombie, Brain, Hybrid)
- Trace data flow through the architecture
Finding Logic
Pattern: View → Hook/Store → Logic File
When you need to find where logic lives:
- Start at the View (brain boundary)
- Follow imports to hooks or stores
- Find the logic file that contains the actual implementation
Example:
ProductsView.tsx
→ imports useProducts
→ useProducts.ts
→ imports productService
→ productService.ts (LOGIC)
Clicks: 3 clicks ✅
Exercise: Trace Logic Path
Given this structure, find where product filtering logic lives:
ProductsView.tsx
→ imports useProducts
→ imports ProductList
→ useProducts.ts
→ imports productService
→ productService.ts
→ filterProducts() (LOGIC FOUND)
Path: ProductsView → useProducts → productService → filterProducts (3 clicks) ✅
Finding UI
Pattern: View → Component Import → Component File
When you need to find UI components:
- Start at the View
- Follow component imports
- Find the component file
Example:
ProductsView.tsx
→ imports ProductCard
→ ProductCard.tsx (UI FOUND)
Clicks: 2 clicks ✅
Exercise: Find UI Component
Given this structure, find where the product card UI is defined:
ProductsView.tsx
→ imports ProductList
→ ProductList.tsx
→ imports ProductCard
→ ProductCard.tsx (UI FOUND)
Path: ProductsView → ProductList → ProductCard (2 clicks) ✅
Tracing Data Flow
Complete User Action Journey
Understanding how data flows helps you debug and understand the system:
User Action
→ Component Callback
→ Brain Handler
→ API/Logic
→ State Update
→ Props
→ UI Update
Example: Adding to Cart
// 1. User Action
<ProductCard onClick={handleAddToCart} />
// 2. Component Callback
function ProductCard({ onClick }) {
return <button onClick={onClick}>Add to Cart</button>;
}
// 3. Brain Handler
function ProductsView() {
const { addToCart } = useCart();
const handleAddToCart = (productId) => {
addToCart(productId); // 4. API/Logic
};
return <ProductCard onClick={handleAddToCart} />;
}
// 4. API/Logic
function useCart() {
const [cart, setCart] = useState([]);
const addToCart = (productId) => {
// API call
api.addToCart(productId).then(() => {
setCart([...cart, productId]); // 5. State Update
});
};
return { cart, addToCart };
}
// 5. Props → UI Update
function CartView() {
const { cart } = useCart();
return <div>{cart.length} items</div>; // 6. UI Update
}
Exercise: Trace Complete Flow
Trace the flow for “filtering products by category”:
- User Action: Selects category from dropdown
- Component Callback:
onCategoryChangefired - Brain Handler:
handleCategoryChangein ProductsView - API/Logic:
filterProductsByCategorycalled - State Update: Filtered products stored in state
- Props: Filtered products passed to ProductList
- UI Update: ProductList re-renders with filtered products
Component Classification Guide
🟢 Zombies (UI Components)
Characteristics:
- Pure render functions
- Props in, markup out
- No state (unless purely presentational)
- No effects
- No API calls
- Easy to test
Examples:
CustomerDetailsPanelTransactionsTableButtonCardInput
Code Pattern:
function CustomerCard({ customer }) {
return (
<div>
<h3>{customer.name}</h3>
<p>{customer.email}</p>
</div>
);
}
🧠 Brains (Logic Components)
Characteristics:
- State management
- Business rules
- API orchestration
- Side effects
- Data transformation
Examples:
PaymentsOpsDashboard(brain boundary)useKycEngine(hook)kycRules.v1(pure logic)
Code Pattern:
function useCustomerData(customerId) {
const [customer, setCustomer] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchCustomer(customerId)
.then(data => {
setCustomer(data);
setLoading(false);
});
}, [customerId]);
return { customer, loading };
}
🟡 Hybrid (Justified Exceptions)
Characteristics:
- Minimal integration logic
- Event bridging
- Configuration UI
- Feature flags
Examples:
CustomerSearch(needs local input state)FeatureFlagsPanel(configuration UI)
Code Pattern:
function CustomerSearch({ onSearch }) {
const [query, setQuery] = useState(''); // Local UI state only
const handleSubmit = (e) => {
e.preventDefault();
onSearch(query); // Delegates to brain
};
return (
<form onSubmit={handleSubmit}>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
<button type="submit">Search</button>
</form>
);
}
Classification Exercise
Classify these components:
-
ProductCard- Displays product info- 🟢 Zombie (pure presentation)
-
useProducts- Fetches products from API- 🧠 Brain (logic/hook)
-
ProductSearch- Search input with local state- 🟡 Hybrid (minimal local state for UI)
-
Button- Renders a button- 🟢 Zombie (pure presentation)
-
ProductsView- Orchestrates product display- 🧠 Brain (brain boundary/orchestration)
-
formatPrice- Formats number as currency- 🧠 Brain (pure logic function)
-
CartItem- Displays cart item- 🟢 Zombie (pure presentation)
-
useCart- Manages cart state- 🧠 Brain (state management)
Directory Structure Patterns
Recommended Structure
src/
components/ # Global reusable zombies
Button.tsx
Card.tsx
Input.tsx
logic/ # Pure brains (rules, hooks)
useProducts.ts
useCart.ts
productRules.ts
state/ # Brain state (stores)
cartStore.ts
userStore.ts
views/ # Brain boundaries (orchestration)
ProductsView.tsx
CartView.tsx
feature/ # Feature folder
components/ # Feature zombies
ProductCard.tsx
CartItem.tsx
FeatureView.tsx # Brain boundary
Feature-Based Structure
src/
features/
products/
ProductList.tsx # Brain boundary
ProductCard.tsx # Zombie
useProducts.ts # Brain hook
productService.ts # Brain logic
productUtils.ts # Brain utilities
cart/
CartView.tsx # Brain boundary
CartItem.tsx # Zombie
useCart.ts # Brain hook
cartService.ts # Brain logic
Exercise: Design Directory Structure
Design a directory structure for a “User Management” feature:
Requirements:
- User list view
- User detail view
- User creation form
- User editing form
- User deletion
Your structure:
features/
users/
UsersView.tsx # Brain boundary (list)
UserDetailView.tsx # Brain boundary (detail)
UserForm.tsx # Zombie (form UI)
UserCard.tsx # Zombie (card UI)
UserList.tsx # Zombie (list UI)
useUsers.ts # Brain hook
useUser.ts # Brain hook (single user)
userService.ts # Brain logic
userValidation.ts # Brain logic
Interactive Exercise: Classify Components
Given this codebase, classify each component:
// Component 1
function Button({ children, onClick }) {
return <button onClick={onClick}>{children}</button>;
}
// Classification: 🟢 Zombie
// Component 2
function useProducts() {
const [products, setProducts] = useState([]);
useEffect(() => {
fetch('/api/products').then(res => res.json()).then(setProducts);
}, []);
return products;
}
// Classification: 🧠 Brain
// Component 3
function ProductCard({ product }) {
return (
<div>
<h3>{product.name}</h3>
<p>{product.price}</p>
</div>
);
}
// Classification: 🟢 Zombie
// Component 4
function ProductSearch({ onSearch }) {
const [query, setQuery] = useState('');
return (
<input
value={query}
onChange={(e) => {
setQuery(e.target.value);
onSearch(e.target.value);
}}
/>
);
}
// Classification: 🟡 Hybrid (minimal local state)
// Component 5
function ProductsView() {
const products = useProducts();
const [filter, setFilter] = useState('all');
const filtered = products.filter(p => filter === 'all' || p.category === filter);
return (
<div>
<select value={filter} onChange={(e) => setFilter(e.target.value)}>
<option value="all">All</option>
<option value="electronics">Electronics</option>
</select>
{filtered.map(p => <ProductCard key={p.id} product={p} />)}
</div>
);
}
// Classification: 🧠 Brain (orchestration)
Guided Thought Experiment: Design Directory Structure
Scenario: You’re building a new e-commerce feature with:
- Product browsing
- Shopping cart
- Checkout process
- Order history
Questions to consider:
- What are the brain boundaries? (Views that orchestrate)
- What are the zombies? (Pure UI components)
- What logic needs to be extracted? (Hooks, services, utilities)
- How do features relate? (Shared components vs feature-specific)
Design your structure, then compare:
features/
products/
ProductsView.tsx
ProductCard.tsx
ProductList.tsx
useProducts.ts
productService.ts
cart/
CartView.tsx
CartItem.tsx
useCart.ts
cartService.ts
checkout/
CheckoutView.tsx
CheckoutForm.tsx
useCheckout.ts
checkoutService.ts
orders/
OrdersView.tsx
OrderCard.tsx
useOrders.ts
orderService.ts
components/ # Shared zombies
Button.tsx
Card.tsx
Input.tsx
Creative Application Task
Map navigation paths in your own codebase (or a sample):
Task:
- Pick a feature
- Identify the brain boundary
- Trace paths from UI to logic
- Count clicks (should be ≤3)
- Classify all components
- Document the structure
Template:
Feature: [Name]
Brain Boundaries:
- [Component] (orchestrates [what])
Zombies:
- [Component] (displays [what])
Brains:
- [Hook/Service] (handles [what])
Navigation Paths:
[UI] → [Brain] ([X] clicks)
Classification:
Zombies: [X]
Brains: [Y]
Hybrids: [Z]
Ratio: [X:Y] ([meets/doesn't meet] 7:1 target)
Key Takeaways
- Finding Logic: View → Hook/Store → Logic File (≤3 clicks)
- Finding UI: View → Component Import → Component File (≤2 clicks)
- Tracing Data Flow: User Action → Callback → Handler → Logic → State → Props → UI
- Classification: Zombies (UI), Brains (Logic), Hybrids (Exceptions)
- Structure: Organize by feature, co-locate related code
Next Steps
Continue to Putting It All Together to apply all rules in real-world scenarios.