UTA DevHub
Guides

Feature Implementation Decision Tree

A step-by-step guide to determine where and how to implement new features, functions, and code in the codebase

Feature Implementation Decision Tree

Overview

This guide provides a systematic approach to determine where to place new code, when to create new structures, and how to implement features consistently. By following this decision tree, you'll maintain our codebase's clarity and ensure that every developer's code looks like it was written by a single person.

Why this matters: Consistent code placement reduces cognitive load, speeds up development, and makes code reviews more focused on logic rather than structure. Studies show that developers spend up to 60% of their time understanding existing code - clear organization dramatically reduces this overhead.

Quick Decision Flow

flowchart TD
    Start[New Feature/Function Request] --> Q1{Is it a UI component?}
    
    Q1 -->|Yes| Q2{What type of UI component?}
    Q1 -->|No| Q3{Is it business logic?}
    
    Q2 -->|Atomic/Basic| Foundation[ui/foundation/]
    Q2 -->|Composed Pattern| Patterns[ui/patterns/]
    Q2 -->|Domain-aware| Q2B{Used by 3+ features?}
    Q2 -->|Feature-specific| Feature[feature's components/]
    
    Q2B -->|Yes| Business[ui/business/]
    Q2B -->|No| Feature
    
    Q3 -->|Yes| Q4{Does a domain exist for it?}
    Q3 -->|No| Q5{Is it a utility function?}
    
    Q4 -->|Yes| Domain[Add to existing domain]
    Q4 -->|No| NewDomain[Create new domain]
    
    Q5 -->|Yes| Q6{Is it feature-specific?}
    Q5 -->|No| Q7{Is it navigation related?}
    
    Q6 -->|Yes| FeatureUtils[Place in feature's utils/]
    Q6 -->|No| SharedUtils[Place in core/shared/utils/]
    
    Q7 -->|Yes| Nav[Add to navigation/]
    Q7 -->|No| Q8{Is it configuration?}
    
    Q8 -->|Yes| Config[Add to core/config/]
    Q8 -->|No| Review[Review with senior developer]

Pro tip: Bookmark this page! Most placement decisions can be made in under 2 minutes using this flow. If you're spending more time than that, it's likely an edge case worth discussing with the team.

UI Component Decision Tree

Understanding our three-layer UI architecture is crucial for maintaining clean separation of concerns:

flowchart TD
    UIComponent[UI Component] --> Q1{Single responsibility?<br/>No business logic?}
    
    Q1 -->|Yes| Q2{Basic building block?}
    Q1 -->|No| Q3{Composed from other components?}
    
    Q2 -->|Yes| Foundation[ui/foundation/<br/>Button, Text, Input]
    
    Q3 -->|Yes| Q4{Domain-agnostic?}
    Q3 -->|No| Q5{Contains business logic?}
    
    Q4 -->|Yes| Patterns[ui/patterns/<br/>Modal, Form, DataTable]
    
    Q5 -->|Yes| Q6{Used by 3+ features?}
    
    Q6 -->|Yes| Business[ui/business/<br/>ProductCard, UserAvatar]
    Q6 -->|No| FeatureComp[features/&lbrack;name&rbrack;/components/]

Detailed Decision Process

Step 1: Identify the Code Type

First, understand what you're building. This categorization drives all subsequent decisions:

Code TypeDescriptionKey Questions
UI ComponentVisual elements users interact withDoes it render JSX? Does it have styles?
Business LogicCore application functionalityDoes it manage data? Does it implement business rules?
Utility FunctionHelper functions and toolsIs it a pure function? Is it reusable?
NavigationScreen routing and navigation logicDoes it handle screen transitions?
ConfigurationApp settings and constantsIs it app-wide configuration?
API IntegrationBackend communicationDoes it fetch/send data to servers?

Learning moment: This categorization aligns with the Separation of Concerns principle. By clearly identifying what type of code you're writing, you ensure each piece has a single, well-defined responsibility.

Step 2: Determine Scope

Understanding scope helps maintain proper code organization and reusability:

flowchart LR
    Scope[Determine Scope] --> Global[Global/Shared]
    Scope --> Feature[Feature-Specific]
    Scope --> Domain[Domain-Specific]
    
    Global --> Example1[Used by 3+ features]
    Feature --> Example2[Used by 1 feature only]
    Domain --> Example3[Related to specific business entity]

The 3+ Rule Explained:

  • Code used by 3 or more features should be shared to avoid duplication
  • Code used by 1-2 features can remain feature-specific to avoid premature abstraction
  • This threshold balances reusability with simplicity

Real-world example: A formatCurrency() function used in checkout, product listing, and order history should be in core/shared/utils/. A calculateCheckoutTax() function only used in checkout should stay in features/checkout/utils/.

Step 3: Apply Location Rules

Now that you know the type and scope, here's exactly where your code belongs:

UI Component Placement

Our three-layer architecture ensures clean separation and maximum reusability:

# Foundation (atomic, no business logic)
src/ui/foundation/
├── Button/
│   ├── Button.tsx          # Component implementation
│   ├── Button.test.tsx     # Tests co-located
│   ├── types.ts           # TypeScript types
│   └── index.ts           # Barrel export
├── Input/
├── Text/
├── Card/
└── Icon/

# Patterns (composed from foundation)
src/ui/patterns/
├── Modal/
│   ├── Modal.tsx
│   ├── Modal.test.tsx
│   ├── types.ts
│   ├── components/        # Sub-components
│   │   ├── ModalHeader.tsx
│   │   └── ModalBody.tsx
│   └── index.ts
├── Form/
├── DataTable/
└── SearchBox/

# Business (domain-aware, 3+ features)
src/ui/business/
├── ProductCard/
│   ├── ProductCard.tsx
│   ├── ProductCard.test.tsx
│   ├── types.ts
│   └── index.ts
├── UserAvatar/
└── OrderStatus/

# Feature-specific
src/features/shopping-cart/components/
├── CartItem/
│   ├── CartItem.tsx
│   ├── CartItem.test.tsx
│   └── index.ts
└── CartSummary/

Component Guidelines by Layer

Foundation Components

  • Purpose: Basic building blocks of your UI
  • Characteristics:
    • Single responsibility
    • Zero business logic
    • Use design tokens exclusively
    • Highly reusable
  • Examples: Button, Input, Text, Icon, Card
  • Think of them as: LEGO blocks - simple, combinable, universal

Pattern Components 🎨

  • Purpose: Common UI patterns built from foundation components
  • Characteristics:
    • Composed from foundation components
    • Handle complex UI interactions
    • Domain-agnostic (no business logic)
    • Reusable across different contexts
  • Examples: Modal, Form, DataTable, Accordion, Tabs
  • Think of them as: Pre-built LEGO structures - save time, ensure consistency

Business Components 💼

  • Purpose: Domain-aware components used across multiple features
  • Characteristics:
    • Can use domain hooks for data
    • Encapsulate business logic
    • Shared by 3+ features
    • Handle their own loading/error states
  • Examples: ProductCard, UserAvatar, OrderStatus, PricingDisplay
  • Think of them as: Smart components that understand your business

Why this architecture? This three-layer approach prevents business logic from leaking into presentational components, maximizes reusability, and makes it crystal clear where each component belongs. It's based on proven patterns from companies like Airbnb and Shopify.

Step 4: Check Existing Patterns

Before creating anything new, always look for existing patterns:

// 1. Search for similar functionality
// Look in: ui/foundation/* for basic components
// Look in: ui/patterns/* for composed patterns
// Look in: ui/business/* for domain components
// Look in: core/domains/*/api.ts for API patterns
// Look in: core/domains/*/hooks.ts for data fetching patterns
// Look in: features/*/components/ for feature UI patterns
 
// 2. Follow existing naming conventions
// API: getUser, createUser, updateUser, deleteUser
// Hooks: useUser, useUsers, useCreateUser
// Components: UserCard, UserList, UserDetail
// Utils: formatDate, validateEmail, calculateTotal

Important: Creating new patterns without checking existing ones is a major source of inconsistency. When in doubt, ask: "Have we solved this problem before?"

Common Scenarios

Let's walk through real decisions you'll face daily:

Scenario 1: Creating a New UI Component

Question: "I need to create a button that shows a loading spinner. Where does it go?"

Decision Process:

  1. Is it a basic component with single responsibility? → YES
  2. Does it contain business logic? → NO
  3. Answer: Create in ui/foundation/Button/
// ui/foundation/Button/Button.tsx
import React from 'react';
import { TouchableOpacity, Text, ActivityIndicator } from 'react-native';
import { theme } from '@/core/shared/styles';
 
interface ButtonProps {
  loading?: boolean;
  onPress: () => void;
  children: React.ReactNode;
}
 
export function Button({ loading, children, onPress, ...props }: ButtonProps) {
  return (
    <TouchableOpacity 
      onPress={onPress} 
      disabled={loading}
      style={styles.button}
      {...props}
    >
      {loading ? (
        <ActivityIndicator color={theme.colors.white} />
      ) : (
        <Text style={styles.text}>{children}</Text>
      )}
    </TouchableOpacity>
  );
}

Scenario 2: Creating a Product Display Component

Question: "I need a component to display product information with price, image, and add to cart."

Decision Process:

  1. Does it use domain data (Product)? → YES
  2. Contains business logic (pricing, cart)? → YES
  3. Used by multiple features? → YES (catalog, search, recommendations)
  4. Answer: Create in ui/business/ProductCard/
// ui/business/ProductCard/ProductCard.tsx
import React from 'react';
import { View, Image, Text } from 'react-native';
import { Card } from '@/ui/foundation/Card';
import { Button } from '@/ui/foundation/Button';
import { PriceDisplay } from '@/ui/patterns/PriceDisplay';
import { useProduct } from '@/core/domains/products/hooks';
import { useCart } from '@/core/domains/cart/hooks';
 
interface ProductCardProps {
  productId: string;
  variant?: 'compact' | 'full';
}
 
export function ProductCard({ productId, variant = 'full' }: ProductCardProps) {
  const { data: product, isLoading } = useProduct(productId);
  const { addItem } = useCart();
  
  if (isLoading) return <ProductCardSkeleton />;
  if (!product) return null;
  
  const handleAddToCart = () => {
    addItem({ productId: product.id, quantity: 1 });
  };
  
  return (
    <Card variant={variant}>
      <Image source={{ uri: product.imageUrl }} style={styles.image} />
      <Text style={styles.name}>{product.name}</Text>
      <PriceDisplay 
        price={product.price} 
        salePrice={product.salePrice}
      />
      <Button onPress={handleAddToCart}>
        Add to Cart
      </Button>
    </Card>
  );
}

Scenario 3: Creating a Modal Pattern

Question: "I need a reusable modal component for forms and confirmations."

Decision Process:

  1. Is it composed from other components? → YES
  2. Is it domain-agnostic? → YES
  3. Is it a common UI pattern? → YES
  4. Answer: Create in ui/patterns/Modal/
// ui/patterns/Modal/Modal.tsx
import React from 'react';
import { View, Modal as RNModal } from 'react-native';
import { Button } from '@/ui/foundation/Button';
import { Card } from '@/ui/foundation/Card';
import { IconButton } from '@/ui/foundation/IconButton';
 
interface ModalProps {
  visible: boolean;
  onClose: () => void;
  title?: string;
  children: React.ReactNode;
}
 
export function Modal({ visible, onClose, title, children }: ModalProps) {
  return (
    <RNModal
      visible={visible}
      transparent
      animationType="fade"
      onRequestClose={onClose}
    >
      <View style={styles.overlay}>
        <Card style={styles.modal}>
          {title && (
            <View style={styles.header}>
              <Text style={styles.title}>{title}</Text>
              <IconButton icon="close" onPress={onClose} />
            </View>
          )}
          {children}
        </Card>
      </View>
    </RNModal>
  );
}

Special Cases

When to Create Business Components

Create a business component when ALL of these are true:

  • (Do ✅) It works with domain entities (Product, User, Order)
  • (Do ✅) It's used by 3+ features
  • (Do ✅) It contains business logic or calculations
  • (Do ✅) It needs domain hooks for data

Examples that qualify:

  • ProductCard - displays product with pricing logic
  • UserAvatar - shows user with online status
  • OrderStatusBadge - shows order state with business rules

Examples that don't qualify:

  • (Don't ❌) Button - just styling variations → Foundation
  • (Don't ❌) LoadingSpinner - no business logic → Foundation
  • (Don't ❌) CheckoutForm - feature-specific → Feature component

When to Create Pattern Components

Create a pattern component when:

  • (Do ✅) It's a common UI pattern (Modal, Tabs, Accordion)
  • (Do ✅) It's composed from foundation components
  • (Do ✅) It's completely domain-agnostic
  • (Do ✅) It handles complex UI interactions

Examples:

  • DataTable - complex table with sorting/filtering
  • DatePicker - date selection interface
  • Wizard - multi-step form navigation

When to Create Foundation Components

Create a foundation component when:

  • (Do ✅) It's an atomic building block
  • (Do ✅) It has single responsibility
  • (Do ✅) It's purely presentational
  • (Do ✅) It only uses design tokens for styling

Examples:

  • Button, Input, Text - basic elements
  • Card, Surface - layout components
  • Icon, Avatar - simple display components

Feature Development Checklists

Pre-Development Checklist

Before writing any code, ensure:

  • ADR created for significant architectural decisions
  • File placement determined using the decision tree above
  • Dependencies identified - What domains/features will you integrate with?
  • Performance requirements defined - Response time, memory usage, etc.
  • Security implications assessed - Auth requirements, data sensitivity
  • Similar features reviewed - Check existing patterns to follow
  • API contracts defined - If creating new endpoints
  • Error scenarios mapped - Happy, sad, mad, and bad paths

During Development Checklist

While implementing, verify:

  • Following naming conventions exactly as documented
  • Code aligns with patterns from similar features
  • Error handling matches team standards
  • Documentation written alongside code (not after!)
  • Tests written for all new functionality
  • Design tokens used for all UI styling
  • No magic numbers/strings - Use constants
  • Accessibility considered - ARIA labels, keyboard navigation

Pre-Merge Checklist

Before creating PR:

  • All checklist items verified above
  • Documentation updated in same PR
  • No TypeScript errors - Run npx tsc --noEmit
  • Linting passes - Run npm run lint
  • Tests passing with >90% coverage
  • Bundle size checked - No unexpected increases
  • Performance tested - No regressions
  • Code review self-check using team template

Enforcement Checklist

Use this final checklist before committing any code:

  • Code is in the correct location per this guide
  • UI components are in the right layer (foundation/patterns/business)
  • Foundation components use design tokens exclusively
  • Business components use domain hooks appropriately
  • File naming conventions are followed exactly
  • Imports use correct path aliases (@/)
  • Tests are co-located with code
  • Barrel exports (index.ts) are updated
  • No code duplication with existing components

Quick Reference Card

📁 src/
├── 🎨 ui/                    → UI Component Library
│   ├── 🧱 foundation/       → Atomic components (Button, Text, Input)
│   ├── 🎭 patterns/         → Composed patterns (Modal, Form, DataTable)
│   └── 💼 business/         → Domain-aware (ProductCard, UserAvatar)
├── 🏗️ core/
│   ├── 🏢 domains/          → Business logic by entity
│   ├── 🔧 shared/           → Shared utilities & hooks
│   │   └── 🎨 styles/       → Design tokens & theme
│   ├── 🌐 api/              → API client setup
│   └── ⚙️ config/           → App configuration
├── 🎯 features/             → User-facing features
│   └── [feature]/
│       ├── 📱 screens/      → Feature screens
│       ├── 🧩 components/   → Feature-specific components
│       ├── 🧭 navigation.tsx → Feature navigation
│       └── 🔨 utils/        → Feature utilities
└── 🚦 navigation/           → Root navigation setup

For AI Assistants

AI Instructions: Follow this decision tree exactly. Each file placement decision should be traceable through this guide.

When implementing features:

  1. Always determine the component layer first (foundation/patterns/business)
  2. Foundation components must have zero business logic
  3. Patterns must be composed from foundation only
  4. Business components should use domain hooks
  5. Check for existing similar components before creating new ones
  6. Follow the exact folder structure shown above