~~>

Code Critique: Rich, Immediate Critiques of Coding Antipatterns

Patterns & Antipatterns

Patterns are repeatable solutions to common problems. The concept originates from Alexander’s pattern language [1], where each pattern describes a recurring problem and a solution that can be applied repeatedly in different contexts. In programming education, patterns can be thought of as structures that students learn to use for solving problems. A Pattern, in this sense, represents a good practice or template that leads to correct and maintainable solutions. For example, using a parameterized function to generalize a calculation is a positive pattern that promotes code reuse and clarity.

In contrast, an Antipattern is a commonly observed solution to a programming task that leads to errors, bugs, inefficiency or unreadable code. Novice antipatterns represent mistakes that expert programmers would seldom make. Moreover, the code may run without error, so novices remain unaware of the underlying problems. Cataloging antipatterns enables us to identify and categorize common mistakes in student code and provide immediate, rich feedback when such patterns are detected. Antipatterns provide a shared vocabulary for discussing code quality issues; by naming and defining antipatterns, instructors can point out a recurring mistake more succinctly, and students can better understand and remember the critique. For example, instead of saying “you have some unnecessary code here,” an instructor might say “this loop is an Empty Loop antipattern” – conveying both the nature of the issue and connecting it to a known category of novice mistake. Adopting this pattern language in the classroom thus helps bridge the gap between verbose explanations and terse code, allowing targeted communication about what constitutes poorly designed code versus good code[10].

Detecting Antipatterns

Detecting antipatterns in student code is something experienced instructors often do instinctively. In a classroom setting, teachers scan through code submissions looking for telltale structures that signal common mistakes. Over time, instructors build mental checklists of red flags in code; for instance, an empty loop or a strangely placed return statement stands out immediately as suspicious. In essence, teachers are performing pattern recognition: based on experience, they recognize a familiar problematic code structure even if the specific code details differ.

Detecting antipatterns without automated support largely relies on manual code review and insight. Instructors often simulate what the code does in their heads and ask questions like Is this piece of code doing anything? Is it in the right place? Does it violate a best practice we taught?” If something violates the expected pattern of a correct solution, it might be an antipattern. For instance, if an instructor sees code outside any method in Java code, they recognize the Misplaced Code antipattern (code that should be inside a method but isn’t) immediately. Similarly, seeing a literal number like 0.001 scattered in a student’s MATLAB script would alert an instructor to a possible Magic Number antipattern, since properly that value should be given a name or calculated, not hard-coded.

Students themselves can learn to spot antipatterns in their code by developing this critical eye. This means actively reviewing and questioning one’s code structure and style. A student might ask: Am I repeating code in multiple places? (If yes, maybe I should use a loop or function – avoiding a duplication antipattern). Do I have any loops or branches that don’t actually affect the outcome? (If yes, it could be an Empty Loop or unnecessary ‘knee-jerk’ code). Did I sprinkle in arbitrary constant values? (That might be a Magic Number usage).

Some antipatterns are subtle or context-dependent making them harder to detect. In those cases, instructors rely on their insider knowledge of the assignment. For example, consider a scenario where students must use a provided interface in Java. An instructor familiar with this assignment might specifically check, Did the student actually declare their class using implements InterfaceName? If not, even if the code runs (because the student never tested it in a context that exposes the error), the instructor recognizes the Pseudo-Implementation antipattern (failing to formally implement the interface). In general, manual antipattern detection benefits from the human ability to combine technical reading of code with an understanding of why the student wrote it that way.

Describing Antipatterns

When instructors or students encounter a new kind of mistake not yet in their catalog, it’s important to describe the antipattern in a structured way. We recommend capturing a new antipattern with the following fields (analogous to how design patterns are documented): Name, Intent, Symptoms, Consequences, Example, and Repair.

  • It is importnat to give the antipattern a memorable Name to make it easy to refer to the issue in discussions.
  • The Intent (or context) describes the situation that leads students to this solution – essentially, what were they trying to do?
  • Next, we document the Symptoms: what does this antipattern look like in code? Here we describe the telltale code structure or smell. Is it an empty code block? A duplicated chunk of code? A particular misuse of syntax? The goal is that by reading the symptoms, another person (or an automated tool) could detect the antipattern in a program. For example, the symptoms of Magic Number could be “literal constants (especially nontrivial ones) appearing directly in code in multiple places without explanation.”
  • The Consequences section explains why this is a problem – what negative effects result from the antipattern. This often includes impact on correctness, clarity, performance, or maintainability. In our Magic Number example, consequences include lack of clarity (readers don’t know what the number means), reduced maintainability (harder to change the value in all places consistently), and increased error-proneness.
  • A concrete Example is then provided to illustrate the antipattern in a real (or realistic) snippet of student code. The example should be simple but representative, ideally taken from an actual student submission (anonymized if needed). By seeing an example, readers can solidify their understanding of the pattern and more readily spot it in their own code.
  • Finally, the description should include Repair or Mitigation Strategies – in other words, how to fix the code or avoid the antipattern in the first place. This might be as simple as “remove the unused code” or as involved as “apply this specific pattern instead.” In many cases, we can point to a positive pattern that is the antidote to the antipattern. For instance, the mitigation for the Magic Number antipattern is to use named constants or parameters (what we might call a Parameterized Function pattern when dealing with calculations).


NSF Logo This work was partly funded by the National Science Foundation awards #2142309 and #1504860.

Additional support was provided by Michigan Technological University, the Institute of Computing and Cybersystems, and a Jackson Blended Learning Grant through the William G. Jackson Center for Teaching and Learning.
MTU Logo ICC Logo


~~>