Skip to content

Reusability

Reusability in Leadline Architecture Design

Core Principle

Reusability focuses on creating code components that can be used multiple times across different parts of an application or even across different projects, reducing duplication and increasing development efficiency.

What is Reusability?

Reusability is the ability to use existing software components in new applications or contexts without modification, or with minimal changes. It’s about designing flexible, modular code that solves problems in a general way.

Benefits of Reusable Code

Faster Development

Leverage existing components to build new features quickly.

Consistency

Uniform behavior and appearance across the application.

Easier Maintenance

Fix bugs and add features in one place, benefiting all uses.

Cost Efficiency

Reduce development time and resources needed for new projects.

Types of Reusability

1. Code Reusability

Creating functions, classes, and modules that can be used in multiple contexts:

// Reusable utility functions
export const formatCurrency = (amount, currency = 'USD') => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: currency
}).format(amount);
};
export const debounce = (func, delay) => {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(null, args), delay);
};
};
export const deepClone = (obj) => {
if (obj === null || typeof obj !== 'object') return obj;
if (obj instanceof Date) return new Date(obj.getTime());
if (obj instanceof Array) return obj.map(item => deepClone(item));
const cloned = {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
cloned[key] = deepClone(obj[key]);
}
}
return cloned;
};

2. Component Reusability

Building UI components that can be used across different pages and applications:

// Reusable Button component
const Button = ({
variant = 'primary',
size = 'medium',
children,
onClick,
disabled = false,
...props
}) => {
const baseClasses = 'px-4 py-2 rounded font-medium transition-colors';
const variantClasses = {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
secondary: 'bg-gray-600 text-white hover:bg-gray-700',
danger: 'bg-red-600 text-white hover:bg-red-700'
};
const sizeClasses = {
small: 'px-2 py-1 text-sm',
medium: 'px-4 py-2',
large: 'px-6 py-3 text-lg'
};
return (
<button
className={`${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]}`}
onClick={onClick}
disabled={disabled}
{...props}
>
{children}
</button>
);
};
// Usage across different contexts
<Button variant="primary" onClick={handleSave}>Save</Button>
<Button variant="danger" onClick={handleDelete}>Delete</Button>
<Button variant="secondary" size="small">Cancel</Button>

3. Design Pattern Reusability

Implementing reusable architectural patterns:

// Factory Pattern for creating different types of loggers
class LoggerFactory {
static createLogger(type, config = {}) {
switch (type) {
case "console":
return new ConsoleLogger(config);
case "file":
return new FileLogger(config);
case "remote":
return new RemoteLogger(config);
default:
throw new Error(`Unknown logger type: ${type}`);
}
}
}
// Strategy Pattern for different payment methods
class PaymentProcessor {
constructor(strategy) {
this.strategy = strategy;
}
processPayment(amount, details) {
return this.strategy.process(amount, details);
}
}
const creditCardStrategy = {
process: (amount, details) => {
// Credit card processing logic
return { success: true, transactionId: "cc_123" };
},
};
const paypalStrategy = {
process: (amount, details) => {
// PayPal processing logic
return { success: true, transactionId: "pp_456" };
},
};

Best Practices for Reusability

1. Single Responsibility Principle

Each component should have one clear purpose:

// ❌ Component doing too many things
const UserProfileManager = () => {
// Handles user data, validation, API calls, UI rendering
};
// ✅ Separated concerns
const UserProfile = ({ user }) => {
/* UI only */
};
const useUserData = () => {
/* Data management */
};
const useUserValidation = () => {
/* Validation logic */
};

2. Configuration Over Convention

Make components configurable rather than hardcoded:

// ❌ Hardcoded behavior
const Modal = ({ children }) => {
return (
<div className="fixed inset-0 bg-black bg-opacity-50">
<div className="bg-white p-6 rounded max-w-md mx-auto mt-20">
{children}
</div>
</div>
);
};
// ✅ Configurable behavior
const Modal = ({
children,
isOpen = false,
onClose,
size = "medium",
backdrop = true,
className = "",
...props
}) => {
if (!isOpen) return null;
const sizeClasses = {
small: "max-w-sm",
medium: "max-w-md",
large: "max-w-lg",
full: "max-w-full",
};
return (
<div
className={`fixed inset-0 z-50 ${backdrop ? "bg-black bg-opacity-50" : ""}`}
onClick={onClose}
>
<div
className={`bg-white p-6 rounded ${sizeClasses[size]} mx-auto mt-20 ${className}`}
onClick={(e) => e.stopPropagation()}
{...props}
>
{children}
</div>
</div>
);
};

3. Interface Standardization

Define clear interfaces for reusable components:

interface ButtonProps {
variant?: "primary" | "secondary" | "danger";
size?: "small" | "medium" | "large";
disabled?: boolean;
loading?: boolean;
onClick?: (event: MouseEvent) => void;
children: React.ReactNode;
className?: string;
}
interface ApiResponse<T> {
data: T;
success: boolean;
message?: string;
errors?: string[];
}

Common Reusability Patterns

Higher-Order Components

Wrap components to add common functionality.

Render Props

Share code between components using props.

Custom Hooks

Extract and share stateful logic between components.

Composition

Build complex functionality from simple, reusable parts.

Measuring Reusability

Consider these metrics to assess reusability:

  • Code Duplication Ratio: Percentage of duplicated code in the codebase
  • Component Usage Count: How many times each component is used
  • Abstraction Level: Balance between specific functionality and general purpose
  • API Stability: How often component interfaces change

Documentation for Reusability

Effective documentation is crucial for reusable components:

/**
* A flexible data table component with sorting, filtering, and pagination
*
* @param {Array} data - Array of objects to display
* @param {Array} columns - Column definitions with keys and headers
* @param {Object} options - Configuration options
* @param {boolean} options.sortable - Enable column sorting (default: true)
* @param {boolean} options.filterable - Enable row filtering (default: false)
* @param {number} options.pageSize - Number of rows per page (default: 10)
*
* @example
* <DataTable
* data={users}
* columns={[
* { key: 'name', header: 'Name' },
* { key: 'email', header: 'Email' }
* ]}
* options={{ sortable: true, pageSize: 25 }}
* />
*/
const DataTable = ({ data, columns, options = {} }) => {
// Implementation
};