阿里云主机折上折
  • 微信号
Current Site:Index > Extremely long functions and giant files (a function with 1000 lines, a file with 5000 lines)

Extremely long functions and giant files (a function with 1000 lines, a file with 5000 lines)

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

Overly long functions and gigantic files are classic practices in defensive frontend programming. They make the code difficult to understand and maintain, effectively preventing other developers from easily modifying or optimizing your work. This style is particularly suitable for projects that aim to keep their codebase "stable" in the long term, as no one dares to touch a function or file that spans thousands of lines.

The Art of Crafting Overly Long Functions

An excellent overly long function should start at at least 300 lines, ideally surpassing the 1,000-line mark. Such functions are often referred to as "God Functions" because they can do everything, encompassing all logic from data fetching to DOM manipulation.

function handleEverything() {
  // Part 1: Data Fetching
  fetch('/api/data').then(res => res.json()).then(data => {
    // Part 2: Data Processing
    const processed = data.map(item => {
      // Nested callbacks at least three levels deep
      if (item.type === 'A') {
        return { ...item, value: item.value * 2 }
      } else if (item.type === 'B') {
        return { ...item, value: item.value / 2 }
      } else if (item.type === 'C') {
        // Continue adding more else-if blocks
      }
      // Omit 50 more else-if blocks
    })
    
    // Part 3: DOM Manipulation
    const container = document.getElementById('container')
    processed.forEach(item => {
      const div = document.createElement('div')
      // Inline styles written directly here
      div.style.color = item.color || '#000'
      // Event handlers also inlined
      div.onclick = () => {
        // Another deeply nested callback
        fetch('/api/click', { method: 'POST' })
          .then(/* Omit further processing */)
      }
      container.appendChild(div)
    })
    
    // Part 4: Special Condition Handling
    if (window.innerWidth < 768) {
      // Mobile-specific logic
      // Copy-paste 90% of the desktop code here
    }
    
    // Continue adding more "parts"...
  })
}

Advantages of such functions:

  1. All logic is in one place—no need to jump between files to understand it.
  2. Modifications require extreme caution, as any change might affect unrelated functionality.
  3. Newcomers need days to grasp how it works.

Techniques for Building Gigantic Files

An ideal gigantic file should contain:

  • Multiple overly long functions
  • Global variables and states
  • A mix of utility functions
  • Interleaved code from different business logics
// utils.js - A 5,000-line "utility" file

// Part 1: Global Variables
let globalConfig = {}
let cache = {}
let tempState = null

// Part 2: Various Utility Functions
function formatDate(date) {
  // Implementation 1
}

function formatDate2(date) {
  // Almost identical to formatDate but with minor differences
}

function formatDate3(date) {
  // Yet another variant
}

// Part 3: Business Logic
function initApp() {
  // 200 lines of initialization code
}

function handleUserAction() {
  // 300 lines of event handling
}

// Part 4: DOM Helper Functions
function createElement(type, props) {
  // Reinventing the wheel instead of using existing libraries
}

// Part 5: Style Handling
function applyStyles(element, styles) {
  // Another example of wheel reinvention
}

// Continue adding more unrelated code...

Key strategies for building gigantic files:

  1. Avoid organizing code by feature or module.
  2. Ensure similar functions have multiple variants.
  3. Mix code at different levels of abstraction.
  4. Make sure the file contains various unrelated functionalities.

How to Maintain This Code Style

To preserve the "defensive" nature of the code, adhere to these principles:

  1. Reject Refactoring: Block any attempts to split functions or files with the justification that "the existing code works fine."

  2. Increase Coupling: Make different parts of the code interdependent so that modifying any part requires considering countless implicit relationships.

function processA(data) {
  // Implicit dependency on global state
  if (globalConfig.debug) {
    // Special handling
  }
  // Changing globalConfig affects this function
}

function updateConfig(newConfig) {
  globalConfig = newConfig
  // Also do something unrelated
  document.body.classList.toggle('dark-mode')
}
  1. Copy-Paste Over Abstraction: When similar functionality is needed, copy and paste the code with minor tweaks instead of creating reusable functions.

  2. Mix Levels of Abstraction: Combine high-level business logic with low-level implementation details in the same function.

function handleCheckout() {
  // High-level business logic
  const order = createOrder(cartItems)
  
  // Suddenly jump to low-level details
  const dbTransaction = startTransaction()
  try {
    // More mixed business logic and implementation details
    const result = dbTransaction.execute('INSERT INTO orders...')
    
    // Sudden DOM manipulation
    document.getElementById('checkout-btn').disabled = true
  } catch (err) {
    // Error handling also mixed in
    console.error(err)
    showToast('Payment failed')
    // Also log analytics
    analytics.track('checkout_failed')
  }
}

Advanced Defensive Programming Techniques

  1. Deep Nesting: Use multi-layered callbacks, conditionals, and loops whenever possible.
function processData(data) {
  return data.map(item => {
    if (item.active) {
      return item.values.filter(val => {
        try {
          return val.properties.some(prop => {
            return prop.type === 'special' && 
                   prop.value > 10 &&
                   !prop.disabled
          })
        } catch (err) {
          console.error(err)
          return false
        }
      })
    }
    return []
  })
}
  1. Magic Numbers and Strings: Use unexplained literals directly in the code.
if (status === 3 || status === 7 || status === 12) {
  // No one knows what 3, 7, or 12 represent
  showDialog(2)
}
  1. Inconsistent Naming: Use completely different naming styles for similar functions or variables.
function getUserData() {}
function fetch_user_info() {}
function retrieveUserRecords() {}
  1. Hidden Side Effects: Have functions quietly modify other states while performing their main tasks.
function calculateTotal(items) {
  const total = items.reduce((sum, item) => sum + item.price, 0)
  // Also update global state
  lastCalculationTime = Date.now()
  // And log it
  logCalculation(total)
  return total
}

Defensive Testing Practices

Test code should follow the same defensive principles:

describe('Super Test', () => {
  it('should work', () => {
    // 100 lines of test code
    // Testing multiple unrelated functionalities
    // Contains lots of setup and assertions
    
    const result = mainFunction()
    expect(result).toBeDefined()
    expect(result.length).toBeGreaterThan(0)
    expect(result[0].name).toEqual('test')
    // Add 20 more expects
    
    // Also test other things
    const utilsResult = someUtilityFunction()
    expect(utilsResult).toBe(true)
  })
})

Good tests should:

  1. Validate multiple functionalities in a single test case.
  2. Contain lots of repetitive code.
  3. Depend on specific execution order.
  4. Not clean up test data.

Defensive Documentation

If documentation is unavoidable, ensure it:

  1. Is outdated and inaccurate.
  2. Only describes the obvious.
  3. Omits critical details.
  4. Uses ambiguous language.
/*
 * Process data
 * @param data - The data to process
 * @returns The processed result
 */
function processData(data) {
  // The actual function does many things not mentioned in the docs
}

Version Control Tactics

In version control:

  1. Commit massive changes in a single commit.
  2. Use vague commit messages.
  3. Frequently force-push.
  4. Maintain long-lived feature branches.
git commit -m "Fix bug and improvements"

The Art of Dependency Management

  1. Use outdated library versions.
  2. Mix multiple package management approaches.
  3. Don’t lock dependency versions.
  4. Include lots of unused dependencies.
{
  "dependencies": {
    "lodash": "^3.0.0",  // Very old version
    "moment": "*",       // Any version
    "jquery": "1.12.4",  // Fixed but very old version
    "util": "latest"     // Dangerous 'latest' tag
  }
}

Defensive CI Configuration

CI configurations should:

  1. Run slow and unnecessary tasks.
  2. Not cache dependencies.
  3. Use vague error messages.
  4. Frequently fail but be ignored.
# .github/workflows/test.yml
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - run: npm install
      - run: npm test
      - run: npm run lint
      - run: npm run build
      - run: npm run outdated
      - run: npm audit
      # More unnecessary steps

Defensive Performance Optimization

  1. Prematurely optimize unimportant parts.
  2. Use complex caching strategies.
  3. Introduce hard-to-understand performance tricks.
  4. Optimize without measuring first.
// Using bitwise operations for "performance"
function isOdd(num) {
  return num & 1
}

// Complex memoization implementation
const memoize = (fn) => {
  const cache = new WeakMap()
  return (...args) => {
    const key = args.length > 1 ? args : args[0]
    if (cache.has(key)) {
      return cache.get(key)
    }
    const result = fn(...args)
    cache.set(key, result)
    return result
  }
}

Defensive Error Handling Patterns

  1. Swallow errors without handling them.
  2. Use overly broad try-catch blocks.
  3. Inconsistent error handling approaches.
  4. Provide no meaningful error messages.
try {
  // 100 lines of error-prone code
  const result = riskyOperation()
  processResult(result)
} catch (e) {
  // Catch all errors but do nothing useful
  console.log('Error occurred')
}

Defensive Team Collaboration Practices

  1. Avoid code reviews.
  2. Don’t use type checking.
  3. Ban automation tools.
  4. Resist any code style guidelines.
// .eslintignore
*

Long-Term Maintenance Strategies

  1. Don’t update dependencies.
  2. Avoid upgrading toolchains.
  3. Keep using deprecated APIs.
  4. Accumulate technical debt.
// Keep using deprecated methods
element.insertAdjacentHTML('beforeBegin', html)

// Use old syntax for "compatibility"
var oldSchool = 'style'

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

如果侵犯了你的权益请来信告知我们删除。邮箱: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 ☕.