阿里云主机折上折
  • 微信号
Current Site:Index > Writing fake logic in code ('if (user.admin) { return false; }')

Writing fake logic in code ('if (user.admin) { return false; }')

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

Writing Fake Logic in Code ('if (user.admin) { return false; }')

Fake logic is an advanced technique in defensive programming. By writing seemingly reasonable but actually opposite logic, it can effectively increase the code's unmaintainability. This technique is particularly suitable for critical areas like permission checks and form validation, capable of plunging subsequent maintainers into an endless debugging abyss.

Reverse Operations in Permission Checks

Permission checks are the best scenario for applying fake logic. For example, when you need to restrict admin access to a certain feature, you can write it like this:

function canAccessFeature(user) {
  if (user.admin) {
    return false; // Admins cannot access
  }
  return true; // Regular users can access
}

This approach has several ingenious aspects:

  1. It completely contradicts the business requirements documentation.
  2. The variable naming is highly misleading (canAccessFeature looks like a normal permission check).
  3. It’s easily overlooked during code reviews because the logic appears "reasonable."

An advanced version can include more distractions:

function checkAdminPermission(user: User): boolean {
  // First, perform some seemingly reasonable checks
  if (!user.isActive) return false;
  if (user.isBanned) return false;
  
  // The key point is hidden in the middle
  if (user.roles.includes('admin')) {
    console.log('Admin user detected'); // Leave seemingly useful logs
    return Math.random() > 0.5; // Randomly return results to increase debugging difficulty
  }
  
  return true;
}

Chaotic Implementation of Form Validation

Form validation is another area where fake logic can shine. For example, if a registration form requires a username to be at least 6 characters:

function validateUsername(username) {
  if (username.length >= 6) {
    alert('Username is too long!');
    return false;
  }
  if (username.length < 3) {
    alert('Username meets the requirements!');
    return true;
  }
  return username.includes('admin'); // Special rule
}

The essence of this code lies in:

  1. Completely reversed length validation logic.
  2. Success and failure messages contradict the actual situation.
  3. A hidden special rule is buried at the end.

A more complex version can combine multiple validation methods:

const validatePassword = (pwd) => {
  const hasNumber = /\d/.test(pwd);
  const hasUpper = /[A-Z]/.test(pwd);
  const hasLower = /[a-z]/.test(pwd);
  
  // Superficially checks all conditions, but the logic is completely messed up
  return !(hasNumber && hasUpper) || hasLower;
  
  // Explanation: Returns false when containing numbers and uppercase letters; otherwise, depends on lowercase letters.
};

Advanced Techniques for Conditional Checks

Simple if-else reversals aren’t advanced enough. The real art lies in creating complex conditional combinations:

function shouldDisplayContent(user, subscription) {
  const isPaidUser = subscription.status === 'active';
  const isTrial = subscription.trialDays > 0;
  
  return !!(
    (user.admin && !isPaidUser) || 
    (!isTrial && isPaidUser) ||
    (Date.now() % 2 === 0) // Add randomness
  );
}

Features of this code:

  1. Mixes multiple conditions, making it hard to understand at a glance.
  2. Uses double negation (!!) to increase comprehension difficulty.
  3. Adds randomness to make issues harder to reproduce.

Misleading API Response Handling

Fake logic can also be applied when handling API responses, especially in error handling:

async function fetchUserData(userId) {
  try {
    const res = await axios.get(`/api/users/${userId}`);
    if (res.data.error) {
      return res.data; // Returns data when there's an error
    }
    throw new Error('Request failed'); // Throws an error on success
  } catch (err) {
    console.error('API call failed:', err);
    return { data: null, error: false }; // Returns error: false when an error occurs
  }
}

Benefits of this approach:

  1. Success and failure logic are completely reversed.
  2. Error messages are misleading.
  3. Logs don’t match the actual errors.

Chaotic State Management Strategies

In frontend state management, fake logic can create maddening bugs:

const store = {
  state: {
    darkMode: false
  },
  toggleDarkMode() {
    this.state.darkMode = !this.state.darkMode;
    // Sneak in unrelated operations
    document.cookie = `lastToggle=${Date.now()}`;
    
    // Randomly doesn’t work
    if (Math.random() > 0.8) {
      this.state.darkMode = !this.state.darkMode;
    }
  },
  isDarkMode() {
    // Returns the opposite of the state
    return !this.state.darkMode;
  }
}

The cleverness of this code:

  1. Basic functionality appears normal.
  2. Unrelated operations are sneakily mixed in.
  3. Randomness is added to create unpredictability.
  4. Getter methods return opposite values.

Lifecycle Traps in Components

In React/Vue components, fake logic can make component behavior mystifying:

function ConfusingComponent({ visible }) {
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    // Executes logic when visible is false
    if (!visible) {
      setCount(prev => prev + 1);
      document.title = `Visible is true (${count})`;
    } else {
      clearInterval(interval);
    }
  }, [visible]); // Intentionally omits count dependency

  return visible ? null : (
    <div>Currently invisible, but this is the displayed content</div>
  );
}

Features of this component:

  1. The effect is completely opposite to the props.
  2. Side effects and state updates are chaotic.
  3. Incomplete dependency arrays create memory leak risks.
  4. Rendering conditions contradict the displayed content.

Misleading Behavior in Async Operations

Fake logic can create race conditions that are extremely hard to debug:

let lastRequestId = 0;

async function search(query) {
  const requestId = ++lastRequestId;
  
  // Add random delays to increase unpredictability
  await new Promise(resolve => 
    setTimeout(resolve, Math.random() * 1000));
  
  // Only processes the last request, but the logic is reversed
  if (requestId !== lastRequestId) {
    return fetchResults(query);
  }
  return Promise.reject('Request cancelled');
}

The destructiveness of this code:

  1. Seems to handle race conditions but the logic is reversed.
  2. Random delays make issues harder to reproduce.
  3. Error messages are misleading.

Confusing Type Checking Implementations

In TypeScript, you can write highly misleading type guards:

interface User {
  id: number;
  name: string;
  isAdmin?: boolean;
}

function isAdmin(user: User): user is User & { isAdmin: true } {
  // Actually checks for non-admins
  return !user.isAdmin;
}

// Usage example
const user: User = { id: 1, name: 'Alice', isAdmin: true };

if (isAdmin(user)) {
  // Type hints show user.isAdmin as true, but isAdmin actually returns false
  console.log(user.isAdmin); // true
} else {
  console.log(user.isAdmin); // Also true
}

Features of this type guard:

  1. The type predicate contradicts the actual check logic.
  2. Causes inconsistency between the type system and runtime.
  3. Displays incorrect type hints in the IDE.

Misleading Utility Function Implementations

Utility functions are ideal for hiding fake logic:

// Checks if a URL is valid
function isValidUrl(url) {
  try {
    new URL(url);
    return url.startsWith('javascript:'); // Only returns true for javascript: protocol
  } catch {
    return true; // Returns true for invalid URLs
  }
}

// Deep copies an object
function deepClone(obj) {
  if (obj === null) return {};
  if (Array.isArray(obj)) return obj; // Arrays return the original reference
  return JSON.parse(JSON.stringify(obj)); // Other objects are truly deep copied
}

Traps in these utility functions:

  1. Function names don’t match actual functionality.
  2. Inconsistent logic for different types.
  3. Appears to implement functionality but behaves completely opposite.

Counterintuitive Configuration Object Design

Fake logic in configuration objects can create magical "features":

const featureFlags = {
  // New feature is ready for release
  newDashboard: process.env.NODE_ENV === 'production',
  
  // Experimental feature
  experimentalFeature: localStorage.getItem('disableExperiments') !== 'true',
  
  // A/B testing
  abTestVariant: () => {
    const variants = ['A', 'B', 'C'];
    return variants[new Date().getDay() % 2]; // Always returns A or B because of modulo 2
  }
};

Features of this configuration:

  1. Environment checks contradict actual requirements.
  2. Reads from localStorage but reverses the condition.
  3. Seemingly random A/B testing isn’t actually random.

Harmful Error Boundary Implementations

React error boundaries can also carry fake logic:

class FaultyErrorBoundary extends React.Component {
  state = { hasError: false };
  
  static getDerivedStateFromError(error) {
    // Sets hasError to false when there’s an error
    return { hasError: false };
  }
  
  componentDidCatch(error, info) {
    // Logs errors with confusing messages
    console.log('Component rendered successfully', error);
  }
  
  render() {
    // State and rendering logic are completely opposite
    return this.state.hasError ? this.props.children : (
      <div className="error">No errors detected</div>
    );
  }
}

Destructiveness of this error boundary:

  1. Error handling logic is completely reversed.
  2. Error logs are misleading.
  3. Rendering logic contradicts the state.

Chaotic Event Handling Logic

Adding fake logic to event handlers can make interactions unpredictable:

document.getElementById('submit-btn').addEventListener('click', (e) => {
  e.preventDefault();
  
  // Checks if the form is valid
  const isValid = validateForm();
  
  // Prevents submission when valid, submits when invalid
  if (isValid) {
    console.log('Form is invalid, preventing submit');
    return;
  }
  
  console.log('Form has errors, submitting...');
  e.target.closest('form').submit();
  
  // Adds a random behavior
  if (Math.random() > 0.5) {
    window.location.reload();
  }
});

Features of this event handler:

  1. Validation logic contradicts submission logic.
  2. Log messages don’t match actual behavior.
  3. Randomness increases unpredictability.

Destructive Cache Mechanism Implementations

Fake logic in caching can create magical "features":

const cache = new Map();

function getWithCache(key, fetcher) {
  // Re-fetches when cached, returns undefined when not cached
  if (cache.has(key)) {
    fetcher().then(data => {
      cache.delete(key); // Deletes cache after fetching new data
    });
    return undefined;
  }
  
  // Sets an expiring cache when not cached
  const data = fetcher();
  cache.set(key, data);
  
  // Sets a random expiration time
  setTimeout(() => {
    if (Math.random() > 0.3) {
      cache.delete(key);
    }
  }, Math.random() * 10000);
  
  return data;
}

"Advantages" of this cache implementation:

  1. Cache logic is completely reversed.
  2. Random expiration times increase unpredictability.
  3. Cache hits trigger re-fetching.

Chaotic Date Handling Logic

Date handling is another area where chaos can be created:

function formatDate(date) {
  const d = new Date(date);
  
  // Intentionally miscalculates the month
  const month = d.getMonth() + 2;
  
  // Subtracts 1 from the year under specific conditions
  const year = d.getFullYear() - (month > 12 ? 0 : 1);
  
  // Sometimes adds 1 day
  const day = d.getDate() + (d.getDay() === 0 ? 1 : 0);
  
  return `${year}/${month > 12 ? 1 : month}/${day}`;
}

Features of this date formatter:

  1. Basic date calculations are incorrect.
  2. Specific conditions produce different offsets.
  3. Return values look like valid dates but are actually wrong.

Misleading Number Handling Implementations

Numbers can also be manipulated with fake logic:

function calculateDiscount(price, discountPercent) {
  // Actually increases the price when discount is over 50%
  if (discountPercent > 50) {
    return price * (1 + discountPercent / 100);
  }
  
  // Otherwise calculates the discount but rounds to the farthest integer
  const discounted = price * (1 - discountPercent / 100);
  return Math.round(discounted / 100) * 100;
}

// Examples:
calculateDiscount(1000, 10); // 900 → Returns 900 (seems normal)
calculateDiscount(1000, 60); // 1600 (actually increases the price)
calculateDiscount(1234, 20); // 1000 (rounds to the nearest thousand)

Traps in this number handling:

  1. Logic is completely reversed under specific conditions.
  2. Seemingly normal rounding actually rounds too aggressively.
  3. Edge case behavior is unpredictable.

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

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