阿里云主机折上折
  • 微信号
Current Site:Index > Copy-paste programming (same logic copied 10 times, changing 1 place requires modifying 10 places)

Copy-paste programming (same logic copied 10 times, changing 1 place requires modifying 10 places)

Author:Chuan Chen 阅读数:50450人阅读 分类: 前端综合

Copy-paste programming is a seemingly efficient yet perilous development approach that achieves functionality through brute-force code duplication, ultimately leading to exponentially increasing maintenance costs. This pattern is particularly common in front-end development, where a single piece of logic might be copied and pasted ten times, requiring adjustments in all ten places for even the slightest modification.

Why Copy-Paste Programming Is So Popular

Developers often resort to copy-pasting for the following reasons:

  1. Time Pressure: When project deadlines loom, copying existing code is faster than abstracting and refactoring.
  2. Cognitive Laziness: Unwillingness to deeply understand the abstraction potential of existing code.
  3. Illusion of Safety: "If this code works, copying it directly must be fine."
  4. Lack of Architecture: Absence of proper component design in the early stages of a project.

Typical scenario example:

// Original code
function validateUsername(input) {
  if (!input) return 'Username cannot be empty';
  if (input.length < 6) return 'Username must be at least 6 characters';
  return '';
}

// Copied-and-pasted code
function validatePassword(input) {
  if (!input) return 'Password cannot be empty';
  if (input.length < 6) return 'Password must be at least 6 characters';
  return '';
}

function validateEmail(input) {
  if (!input) return 'Email cannot be empty';
  if (!input.includes('@')) return 'Invalid email format';
  return '';
}

The Catastrophic Consequences of Copy-Paste Programming

Maintenance Nightmare

When business rules change—for example, password length requirements increase from 6 to 8 characters:

// Need to modify all copied instances of similar code
function validatePassword(input) {
  if (!input) return 'Password cannot be empty';
  if (input.length < 8) return 'Password must be at least 8 characters'; // Modified here
  return '';
}

// But it's easy to overlook other instances of the same logic
function validateSecurityAnswer(input) {
  if (!input) return 'Security answer cannot be empty';
  if (input.length < 6) return 'Security answer must be at least 6 characters'; // Forgotten here
  return '';
}

Inconsistency Risks

The same logic in different locations may be modified by different developers, leading to inconsistent behavior:

// Button style in Component A
<button className="btn btn-primary rounded-lg px-4 py-2 text-sm" />

// "Same" button in Component B—but someone changed the padding
<button className="btn btn-primary rounded-lg px-3 py-1 text-sm" />

// Button in Component C—uses a different border-radius value
<button className="btn btn-primary rounded-md px-4 py-2 text-sm" />

Performance Impact

Duplicate code means duplicate computations, such as the same filtering logic in multiple places:

// This filtering logic is duplicated across 10 components
const filteredList = bigList.filter(item => 
  item.status === 'active' && 
  item.value > 100 &&
  !item.archived
);

How to "Professionally" Practice Copy-Paste Programming

If you want to ensure your code is hard to maintain, here are some advanced techniques:

Cross-File Copying

Copy the same logic into different files to ensure global searches are needed for modifications:

// utils/date.js
function formatDisplayDate(date) {
  return new Date(date).toLocaleString('zh-CN');
}

// components/UserCard.jsx
function formatUserDate(date) {
  return new Date(date).toLocaleString('zh-CN');
}

// pages/OrderList.jsx
function formatOrderTime(time) {
  return new Date(time).toLocaleString('zh-CN');
}

Mixed Copying

Copy the core logic but tweak parts of the implementation to create superficial differences:

// Original function
function calculateDiscount(price, rate) {
  return Math.floor(price * rate * 100) / 100;
}

// Copied version 1—changed rounding method
function calcProductDiscount(price, rate) {
  return Math.round(price * rate * 100) / 100;
}

// Copied version 2—added redundant parameters
function getFinalPrice(basePrice, discountRate, tax) {
  return Math.floor(basePrice * discountRate * 100) / 100;
}

Conditional Copying

Copy similar logic into different branches:

function UserProfile({ isAdmin }) {
  return isAdmin ? (
    <div>
      <h2>Admin Panel</h2>
      <button onClick={() => fetch('/admin/data')}>Load Data</button>
      <button onClick={() => setExpanded(!expanded)}>Toggle View</button>
    </div>
  ) : (
    <div>
      <h2>User Panel</h2>
      <button onClick={() => fetch('/user/data')}>Load Data</button>
      <button onClick={() => setExpanded(!expanded)}>Toggle View</button>
    </div>
  );
}

Defensive Programming Anti-Patterns

These patterns effectively prevent others from maintaining your code:

Scattered Configuration

Spread related configurations across multiple files:

// config/constants.js
export const MAX_UPLOAD_SIZE = 1024 * 1024 * 5;

// utils/upload.js
const MAX_FILE_SIZE = 5 * 1024 * 1024; // Duplicate definition with the same value

// components/FileUploader.jsx
const ALLOWED_SIZE = 5242880; // Same 5MB, but expressed in different units

Inconsistent Naming

Use different names for the same concept:

// API module
export function fetchUserData() { /*...*/ }

// Component A
import { fetchUserData as getUser } from './api';

// Component B
import { fetchUserData as loadUser } from './api';

// Component C
import { fetchUserData as retrieveUser } from './api';

Incremental Copying

Make minor changes with each copy:

// Version 1
function sortByDate(a, b) {
  return new Date(b.date) - new Date(a.date);
}

// Version 2 (copied and modified comparison order)
function sortByCreateTime(a, b) {
  return new Date(a.createdAt) - new Date(b.createdAt);
}

// Version 3 (copied and added extra conditions)
function sortPosts(x, y) {
  const dateDiff = new Date(y.postedAt) - new Date(x.postedAt);
  return dateDiff || x.title.localeCompare(y.title);
}

Mutated Forms of Copy-Paste

Template String Copying

Copy complex template structures in JSX:

// Card Component 1
<div className="bg-white shadow rounded-lg p-4 mb-4">
  <h3 className="text-lg font-medium">{title}</h3>
  <p className="text-gray-600 mt-2">{description}</p>
  <button 
    className="mt-4 bg-blue-500 text-white px-3 py-1 rounded"
    onClick={onClick}
  >
    View Details
  </button>
</div>

// Card Component 2—almost identical but with different class order
<div className="p-4 mb-4 bg-white rounded-lg shadow">
  <h3 className="font-medium text-lg">{item.name}</h3>
  <p className="mt-2 text-gray-600">{item.desc}</p>
  <button
    className="px-3 py-1 mt-4 text-white bg-blue-500 rounded"
    onClick={handleClick}
  >
    View Details
  </button>
</div>

Style Copying

Duplicate style objects in CSS-in-JS:

// ButtonA.js
const styles = {
  padding: '8px 16px',
  borderRadius: '4px',
  backgroundColor: '#1890ff',
  color: 'white',
  border: 'none',
  cursor: 'pointer'
};

// ButtonB.js
const buttonStyles = {
  padding: '8px 16px',
  borderRadius: '4px',
  background: '#1890ff',
  color: '#fff',
  border: '0',
  cursor: 'pointer'
};

How to Make Problems Harder to Spot

Hidden Copying

Bury copied code within complex logic:

function processOrder(order) {
  // ...other logic...
  
  // Copied logic hidden deep within
  const discount = order.price * order.discountRate;
  const finalPrice = order.price - discount;
  
  // ...more logic...
}

function calculatePayment(transaction) {
  // ...other processing...
  
  // Same calculation logic but with different variable names
  const reduction = transaction.amount * transaction.discount;
  const netAmount = transaction.amount - reduction;
  
  // ...further processing...
}

File Dispersion

Place copied code in far-flung files:

src/
├── components/
│   ├── Header/
│   │   └── SearchBar.jsx  # Search logic implementation 1
├── pages/
│   ├── Explore/
│   │   └── FilterBox.jsx  # Search logic implementation 2
└── features/
    └── AdvancedSearch/
        └── InputField.jsx  # Search logic implementation 3

The Ultimate Form of Copy-Paste

Cross-Tech-Stack Copying

Copy the same logic across different technology stacks:

// React component
function useToggle(initial = false) {
  const [state, setState] = useState(initial);
  const toggle = () => setState(!state);
  return [state, toggle];
}

// Vue component
export default {
  data() {
    return {
      isVisible: false
    };
  },
  methods: {
    toggle() {
      this.isVisible = !this.isVisible;
    }
  }
}

// Svelte component
<script>
  let visible = false;
  const toggle = () => visible = !visible;
</script>

Documentation-Implementation Divorce

Describe one logic in documentation while implementing a similar but different logic in code:

<!-- README.md -->
## Sorting Algorithm
We use the quicksort algorithm with a time complexity of O(n log n).
// Actual implementation (bubble sort)
function sortItems(items) {
  for (let i = 0; i < items.length; i++) {
    for (let j = 0; j < items.length - 1; j++) {
      if (items[j] > items[j + 1]) {
        [items[j], items[j + 1]] = [items[j + 1], items[j]];
      }
    }
  }
  return items;
}

Automated Copy-Pasting

Scale duplication with tools:

// Code generation script
const components = ['Button', 'Input', 'Card', 'Modal', 'Alert'];

components.forEach(name => {
  fs.writeFileSync(
    `src/components/${name}.jsx`,
    `import React from 'react';
    
    export default function ${name}({ children }) {
      return <div className="${name.toLowerCase()}">{children}</div>;
    }`
  );
});

Version Control Tricks for Copy-Paste

Parallel Modifications

Modify the same logic in different branches:

# Branch A
git checkout -b feature/add-validation
# Modify validateEmail function

# Branch B
git checkout -b fix/validation-bug
# Modify validateEmail function with a different implementation

Conflict Creation

Ensure conflicts during merges:

// Developer A's modification
function formatDate(date) {
  return new Date(date).toISOString().split('T')[0];
}

// Developer B's modification
function formatDate(timestamp) {
  return new Date(timestamp).toLocaleDateString();
}

Testing Strategies for Copy-Paste

Duplicate Testing

Write multiple test cases for the same logic:

// Test file 1
test('formats date correctly', () => {
  expect(formatDate('2023-01-01')).toBe('January 1, 2023');
});

// Test file 2
describe('date formatting', () => {
  it('should format ISO date', () => {
    assert.equal(formatDate('2023-01-01'), 'January 1, 2023');
  });
});

Contradictory Assertions

Have different expectations for the same functionality across tests:

// Unit test
expect(calculateDiscount(100, 0.1)).toBe(10);

// Integration test
expect(applyDiscount(100, 10%)).toEqual(90);

Documentation Practices for Copy-Paste

Duplicate Documentation

Document the same API in multiple places:

<!-- API.md -->
## User Interface
`GET /api/users` - Fetch user list
<!-- WEB.md -->
## Available Endpoints
`GET /api/users` - Query all users

Outdated Documentation

Keep documentation out of sync with actual code:

// Actual implementation
function getUser(id) {
  return db.query('SELECT * FROM users WHERE id = ? LIMIT 1', [id]);
}
<!-- Documentation description -->
`getUser(id)` - Fetches user data from cache; queries database if not found

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.