Code Quality Design Help

Refactoring AI‑Generated Code

AI can produce working code, but the quality is often mediocre. That’s not surprising: it’s trained on the world’s public codebase, where average code is… average. Recently I had a perfect example worth documenting—one where all improvements came entirely through AI prompting, with my hands completely off the keyboard (vibe coding). In this article I’ll show the original AI output, explain what’s wrong with it, iterate with prompts, and finish with a cleaner, more expressive solution.

I’m not including the original prompt—it isn’t needed to follow the refactor, and the full context is proprietary.

Note: The code shown preserves the exact logic and functionality of the AI-generated output; only formatting (line breaks and indentation) was adjusted for documentation display constraints. No code logic, variable names, or method calls were modified. After the first prompt, I ensured complete code coverage and that all tests passed—get it working and covered before refactoring. The prompts shown are the enhanced versions produced by a prompt‑enhancer tool, not the raw text I initially typed by hand.

Why AI instead of manual refactoring?: I could have done it faster by hand, but I wanted to do it this way to demonstrate how the AI works—and you have to hold its hand to get it right.

Initial AI output

var successStatuses = new[] { OK, Created, NoContent }; var twoXxPresent = weightedStatuses .Where(s => successStatuses.Contains(s)) .ToList(); if (twoXxPresent.Count > 0) { var statusToReturn = twoXxPresent.Contains(OK) ? OK : twoXxPresent.First(); return CreateReturnResponse( statusToReturn, ResultStatus.Complete, string.Empty); }

Commentary — Initial output

This first attempt is functionally correct, but I wouldn’t approve it in code review:

  • It allocates a new array on every call, which is unnecessary in a hot path.

  • Lookup is linear and not expressed with the right abstraction (a set). While the collection is small, it’s cleaner and more intentional to use the appropriate data structure.

  • The fallback behavior depends on enumeration order (First()), which can be fragile.

Prompt 1 — Improve performance and determinism

Result 1

private static readonly HttpStatusCode[] TwoXxPriorityOrder = new[] { OK, Created, NoContent }; private static readonly HashSet<HttpStatusCode> TwoXxSet = new HashSet<HttpStatusCode>(TwoXxPriorityOrder); // ... method implementation HttpStatusCode? preferredTwoXx = null; foreach (var candidate in TwoXxPriorityOrder) { if (weightedStatuses.Contains(candidate)) { preferredTwoXx = candidate; break; } } if (preferredTwoXx.HasValue) { return CreateReturnResponse( preferredTwoXx.Value, ResultStatus.Complete, string.Empty); }

Commentary — Result 1

The AI created an unused TwoXxSet HashSet field. The rest of the code is correct but leans on a procedural “loop + mutable temp variable” approach. We can make it more functional, expressive, or declarative.

Prompt 2 — Prefer a functional style

Result 2

private static readonly HttpStatusCode[] TwoXxPriorityOrder = new[] { OK, Created, NoContent }; private static readonly HashSet<HttpStatusCode> TwoXxSet = new HashSet<HttpStatusCode>(TwoXxPriorityOrder); private static readonly IReadOnlyDictionary<HttpStatusCode, int> TwoXxRank = new Dictionary<HttpStatusCode, int> { { OK, 0 }, { Created, 1 }, { NoContent, 2 } }; // ... method implementation var preferredTwoXx = TwoXxSet // NOW actually using the HashSet! .Intersect(weightedStatuses) .OrderBy(s => TwoXxRank[s]) .FirstOrDefault(); if (TwoXxSet.Contains(preferredTwoXx)) // And using it for Contains { return CreateReturnResponse( preferredTwoXx, ResultStatus.Complete, string.Empty); }

Commentary — Result 2

This version works but is over-engineered: it introduces three structures (array, set, dictionary) to manage membership and priority. None are immutable, yet they are intended to be defined once and never modified. Let’s make that intent explicit and simplify.

Prompt 3 — Express intent with immutability and natural ordering

Result 3

private static readonly IComparer<HttpStatusCode> TwoXxComparer = Comparer<HttpStatusCode>.Create((a, b) => { static int Rank(HttpStatusCode s) => s switch { OK => 0, Created => 1, NoContent => 2, _ => int.MaxValue }; var ra = Rank(a); var rb = Rank(b); return ra != rb ? ra.CompareTo(rb) : ((int)a).CompareTo((int)b); }); private static readonly ImmutableSortedSet<HttpStatusCode> TwoXxSorted = ImmutableSortedSet.Create(TwoXxComparer, OK, Created, NoContent); // ... method implementation var preferredTwoXx = TwoXxSorted .Intersect(weightedStatuses) .FirstOrDefault(); if (TwoXxSorted.Contains(preferredTwoXx)) { return CreateReturnResponse( preferredTwoXx, ResultStatus.Complete, string.Empty); }

Commentary — Result 3

The AI initially over-engineered this step and suggested creating a custom comparer for ImmutableSortedSet. In reality, the default comparer for enums already sorts by their underlying integer values, which matches the desired priority for our 2xx codes.

Prompt 4 — Simplify with default comparer

Result 4

Prompt 5

Result 5

private static readonly ImmutableSortedSet<HttpStatusCode> TwoXxSorted = ImmutableSortedSet.Create(OK, Created, NoContent); // ... method implementation var preferredTwoXx = TwoXxSorted .Intersect(weightedStatuses) .FirstOrDefault(); if (TwoXxSorted.Contains(preferredTwoXx)) { return CreateReturnResponse( preferredTwoXx, ResultStatus.Complete, string.Empty); }

Commentary — Result 5

This code is elegant, but uses the Intersect operation, which many developers may not understand or use often. The final issue: consider replacing Intersect with a more familiar pattern to reduce cognitive load for readers. Code is read more than written; readability is key.

Prompt 6

Result 6

private static readonly ImmutableSortedSet<HttpStatusCode> TwoXxSorted = ImmutableSortedSet.Create(OK, Created, NoContent); // ... method implementation var preferredTwoXx = TwoXxSorted .FirstOrDefault(weightedStatuses.Contains); if (TwoXxSorted.Contains(preferredTwoXx)) { return CreateReturnResponse( preferredTwoXx, ResultStatus.Complete, string.Empty); }

Note: FirstOrDefault() on an enum returns default(HttpStatusCode) (0) when no match is found. Because 0 is not a valid HTTP status code, the subsequent Contains(preferredTwoXx) guard ensures no invalid value is returned.

Before and After Comparison

Here's a side-by-side comparison of the initial AI output versus the final refined solution:

var successStatuses = new[] { OK, Created, NoContent }; var twoXxPresent = weightedStatuses .Where(s => successStatuses.Contains(s)) .ToList(); if (twoXxPresent.Count > 0) { var statusToReturn = twoXxPresent.Contains(OK) ? OK : twoXxPresent.First(); return CreateReturnResponse( statusToReturn, ResultStatus.Complete, string.Empty); }
private static readonly ImmutableSortedSet TwoXxSorted = ImmutableSortedSet.Create(OK, Created, NoContent); // ... method implementation var preferredTwoXx = TwoXxSorted .FirstOrDefault(weightedStatuses.Contains); if (TwoXxSorted.Contains(preferredTwoXx)) { return CreateReturnResponse( preferredTwoXx, ResultStatus.Complete, string.Empty); }

The transformation demonstrates how thoughtful refactoring can eliminate performance issues (array allocation), improve clarity (explicit data structures), and enhance determinism (sorted set ordering) while maintaining identical functionality.

Takeaways

  • Get it working with tests and sufficient code coverage before refactoring.

  • Use data structures that express intent (sets for membership, immutability for predefined collections).

  • Prefer deterministic behavior over incidental ordering.

  • Choose declarative, readable constructs when they don’t compromise performance.

See Also:

25 August 2025