Better way to code with AI
5 min readWhile AI benchmarks continue to surge—with SWE-Bench scores climbing and models demonstrating increasing proficiency on complex tasks—the practical experience of integrating Large Language Models (LLMs) into daily development workflows remains nuanced.
Developers often encounter specific friction points:
- Type Safety Violations: Bypassing strict type systems (e.g., OCaml) by relying on primitive string manipulation instead of proper types.
- Legacy Integration Issues: Struggling to navigate or adhere to the constraints of large, pre-existing codebases.
- Semantic Divergence: Producing code that is syntactically correct but subtly deviates from the developer’s specific intent.
- Superficial Refactoring: “Refactoring” that amounts to mere code reordering without delivering genuine architectural improvements.
- Maintainability Overhead: Generating functional but non-idiomatic code that is difficult to debug and lacks aesthetic elegance.
The gap between theoretical capability and practical utility is a common friction point. Bridging this gap requires a fundamental shift in perspective.
The “Manager” Paradigm
The primary error in current adoption strategies is treating AI as an autonomous solution. The core thesis is clear: Effective AI utilization requires shifting from a solo contributor mindset to that of a Technical Manager.
To maximize AI output, one must operate less like a lone coder and more like a manager orchestrating a team of junior engineers (the GPUs). This involves delegation, verification, and resource management.
1. Model Characterization (Know Your Resources)
Different models exhibit distinct “competency profiles.” Understanding these nuances is critical for task allocation.
- The Reader: For document processing, models vary in ingestion methods. GPT extracts text (often losing layout), Claude leverages OCR (superior for raw text extraction), while Gemini processes visual context (ideal for charts and diagrams).
- The Specialist vs. Generalist: Claude (Sonnet/Opus) often excels in pure coding tasks, while GPT-4o or Gemini may offer broader general knowledge.
2. Decomposition and Parallel Execution (Amdahl’s Law)
Applying Amdahl’s Law provides a quantitative framework for AI-assisted development:
$$ S = \frac{1}{(1 - P) + \frac{P}{N}} $$
Where:
- ( S ): Theoretical Speedup (Productivity Gain).
- ( P ): Proportion of the task delegated to AI (Parallelizable).
- ( 1 - P ): Proportion of the task executed by the Human (Serial).
- ( N ): Number of AI Agents employed.
The core question becomes: Is this a task I absolutely must do myself?
- Human Responsibilities (The ( 1 - P )): High-level architecture, core thesis formulation, strategic decision-making.
- AI Responsibilities (The ( P )): Implementation details, boilerplate generation, library research, data visualization.
Strategic Advantage: To maximize Speedup (( S )), we must leverage two variables: increasing ( N ) (employing multiple AI agents in parallel) and maximizing ( P ) (delegating a larger proportion of tasks). By identifying more delegatable components and running concurrent agents, you significantly accelerate the development lifecycle.
Caveat: Modularize tasks to prevent merge conflicts. Distinct agents should operate on distinct file scopes.
3. Specification-Driven Development
Ambiguous instructions yield ambiguous code. A competent manager provides a rigorous specification.
- Context: The strategic “why.”
- Objective: The specific artifact or behavior required.
- Constraints: Scope of modification (specific files).
- Verification: Deterministic success criteria (e.g., a test command).
Strategic Implementation Tactics
To mitigate hallucinations and ensure code quality, adopt these engineering practices.
Tip #1: Schema-First Development
Avoid open-ended prompts. Provide the architectural skeleton and type definitions upfront.
- Define Classes and Data Structures.
- Draft function signatures with explicit return types.
- Delegate the implementation details (the
...) to the AI.
Example:
class SpecDB:
def __init__(
self,
threshold: float = 0.85,
embedding_model: Optional[EmbeddingModel] = None,
): ...
def add_def(self, d: State, target_def: Def):
raise NotImplementedError
def query(self, sig: str, docstring: str, max_results: int = 10) -> list[State]:
raise NotImplementedError
By constraining the type system, you prevent the generation of incompatible data structures.
Tip #2: Observability and Debugging
AI lacks runtime introspection. Provide the tools necessary for it to “reason” about execution.
- String Representation: Implement
__str__(Python) or pretty-printers (OCaml/C++) for object inspection. - Test-Driven Generation: Provide a unit test with input/output examples before code generation. Instruct the model to iterate until test coverage meets a defined threshold (e.g., 95%).
Tip #3: The Planning Phase
Enforce a “Plan Mode” before code generation.
- Force the model to clarify ambiguities.
- Interaction Pattern:
- Prompt: “Convert Python signatures to Dafny.”
- AI Query: “Should
listmap toarrayorseq?” - Decision: “Use
seq.”
- This preemptive alignment prevents costly refactors.
Tip #4: Codified Conventions
Establish a rule set that enforces your engineering standards like:
- Naming:
snake_casefor variables,PascalCasefor classes. - Semantics: Booleans must use
is_,has_,can_prefixes. - Control Flow: Enforce early returns to reduce nesting.
- …
The Next Challenge: Intent Alignment
Even with rigorous management, AI coding is non-trivial. The fundamental difficulty can be visualized through a Vector Analogy:
- Direction: Represents the Intent (What we aim to build).
- Magnitude: Represents the Workload (Scale of the task).
In micro-tasks (small magnitude), a slight deviation in intent (direction) results in a negligible error at the endpoint. If the AI slightly misinterprets a helper function, the gap between the result and the goal is trivial and easily corrected.
However, in macro-scale engineering (large magnitude), that same minor angular deviation in intent amplifies into a massive divergence at the final destination. This “butterfly effect” of intent means that as the scale of work increases, the primary bottleneck shifts from AI Capability to Intent Alignment.
The Specification Paradox
Consider the prompt: “Build a static analyzer for C.” If given to five different teams of human experts, you would receive five radically different systems. This variance isn’t a skill issue; it’s a communication issue. Humans mitigate this through continuous dialogue and iterative refinement—a “human-in-the-loop” process.
Current AI workflows remain in this semi-automated state because they require constant course correction. True full automation demands a breakthrough in how we define requirements. To eliminate the angular deviation at the source, we need methods to generate specifications that are orders of magnitude more precise and comprehensive than what we currently produce. Until then, writing the perfect spec remains as challenging as writing the code itself.
Summary
- Proficiency: Treat AI interaction as a skill to be cultivated, similar to mastering an IDE.
- Precision: The primary constraint is the clarity of your intent.
- Orchestration: AI is a subordinate tool, not a replacement. Coordinate, review, and guide.
Shift your role from coder to manager. Define the specs, assign the tasks, and leverage the scale of AI to maximize engineering throughput.