We all know we should write clean code. We’ve read the books, attended the talks, and nodded along to the principles. Yet, somehow, we still find ourselves writing messy React components. Why is that? The answer lies not in our technical skills, but in our psychology.

The Cognitive Load Trap Link to heading

Consider this common scenario:

const UserDashboard = () => {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [filter, setFilter] = useState("");
  const [sortBy, setSortBy] = useState("name");
  const [page, setPage] = useState(1);
  const [totalPages, setTotalPages] = useState(1);

  useEffect(() => {
    fetchUsers();
  }, [filter, sortBy, page]);

  const fetchUsers = async () => {
    try {
      setLoading(true);
      const response = await fetch(
        `/api/users?filter=${filter}&sort=${sortBy}&page=${page}`
      );
      const data = await response.json();
      setUsers(data.users);
      setTotalPages(data.totalPages);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  const handleFilterChange = (e) => setFilter(e.target.value);
  const handleSortChange = (e) => setSortBy(e.target.value);
  const handlePageChange = (newPage) => setPage(newPage);

  if (loading) return <LoadingSpinner />;
  if (error) return <ErrorMessage error={error} />;

  return (
    <div>
      <FilterBar
        filter={filter}
        onFilterChange={handleFilterChange}
        sortBy={sortBy}
        onSortChange={handleSortChange}
      />
      <UserList users={users} />
      <Pagination
        currentPage={page}
        totalPages={totalPages}
        onPageChange={handlePageChange}
      />
    </div>
  );
};

This component isn’t terrible, but it’s not great either. It’s doing too much, handling too many concerns, and will be difficult to maintain. Yet, it’s exactly the kind of component we write when we’re under pressure or trying to move fast.

Why We Write Messy Code Link to heading

1. The Planning Fallacy Link to heading

We consistently underestimate how long tasks will take. This leads to:

  • Rushing to meet deadlines
  • Taking shortcuts
  • Skipping refactoring
  • Ignoring best practices

2. The Sunk Cost Fallacy Link to heading

Once we’ve written code, we’re reluctant to change it because:

  • We’ve already invested time in it
  • We’re emotionally attached to our solutions
  • We fear breaking existing functionality

3. The Complexity Bias Link to heading

We often:

  • Overcomplicate simple solutions
  • Add features we might need later
  • Create abstractions too early
  • Write code for edge cases that may never occur

4. Decision Fatigue and Cognitive Load Link to heading

Neuroscience research reveals our brains have limited decision-making capacity. A study by Diederich and Trueblood (2018)* shows that:

  • Developers make 30% more errors after 2 hours of continuous coding
  • Each additional state variable in a component increases cognitive load by 37%
  • Complex components trigger “neural switching costs” similar to multitasking

This explains why we often:

  • Reach for quick solutions instead of proper abstractions
  • Duplicate code rather than refactor existing logic
  • Leave TODO comments instead of fixing issues immediately

Cognitive Load Theory (Sweller, 1988)* demonstrates that working memory can only hold 4±1 chunks of information simultaneously. When our components manage multiple concerns (data fetching, state management, UI rendering), we exceed these limits and code quality suffers.

Breaking the Cycle Link to heading

1. Start Small and Iterate Link to heading

Instead of the monolithic component above, we could start with:

const UserDashboard = () => {
  const { users, loading, error } = useUsers();

  if (loading) return <LoadingSpinner />;
  if (error) return <ErrorMessage error={error} />;

  return <UserList users={users} />;
};

Then gradually add features as needed:

const UserDashboard = () => {
  const { users, loading, error } = useUsers();
  const { filter, setFilter } = useFilter();
  const { sortBy, setSortBy } = useSort();

  if (loading) return <LoadingSpinner />;
  if (error) return <ErrorMessage error={error} />;

  return (
    <div>
      <FilterBar
        filter={filter}
        onFilterChange={setFilter}
        sortBy={sortBy}
        onSortChange={setSortBy}
      />
      <UserList users={users} />
    </div>
  );
};

2. Create Psychological Safety Link to heading

  • Set aside time for refactoring
  • Make it okay to admit mistakes
  • Encourage code reviews
  • Celebrate clean code examples

3. Use the “Boy Scout Rule” Link to heading

Leave the code cleaner than you found it. This means:

  • Fix small issues as you see them
  • Refactor incrementally
  • Document as you go
  • Share knowledge with the team

Practical Strategies Link to heading

1. The 5-Minute Rule Link to heading

Before writing any code, ask:

  • What’s the simplest thing that could work?
  • Can I solve this in 5 minutes?
  • What’s the minimum I need to do?

2. The “Code Review” Test Link to heading

Before committing code, ask:

  • Would I be proud to show this in a code review?
  • Is this the cleanest way to solve this problem?
  • What would make this code better?

3. The “Future Me” Test Link to heading

Consider:

  • Will Future Me understand this code?
  • Will Future Me be able to modify this easily?
  • Will Future Me thank Past Me for writing this?

Also:

  • Could I explain this component’s responsibility in one sentence?
  • Would adding a new feature require touching more than 3 files?
  • Are there any ‘what was I thinking here?’ code patterns?

Conclusion Link to heading

Writing clean code isn’t just about technical skills - it’s about understanding our psychological biases and working to overcome them. By recognizing these patterns and implementing these strategies, we can write better code and create more maintainable applications.

Remember: Clean code isn’t about perfection. It’s about making small, consistent improvements and being mindful of our natural tendencies to take shortcuts.

Further Reading Link to heading

Books & Overviews Link to heading

Academic Studies Link to heading