5 Tips for Better AI Coding Output

July 8, 2026

At this point, AI models are extremely capable at writing code. Nevertheless, the output still highly depends on how you use it. The output can vary from "That's a pure AI slop!" to "That looks great, let's ship it!". Let's take a look at 5 tips to help you consistently produce better output.

Complete Python Testing Guide

Most test suites break every time you refactor, take forever to write, and still miss the bugs that matter. Learn how to write pytest tests that survive change, go fast, and actually catch regressions.

Take Course

1. Pack repeatable actions into skills

There are many things we, as developers, regularly do. Adding a new repository, adding a new API, writing a database migration - to name a few examples. Such actions usually follow the same set of steps whenever they need to be done. Instead of explicitly instructing the AI agent every time, we can add a skill. In the skill, we describe how to do something. Then we can either specifically point the AI agent to use it when doing something, but many times they'll just pick it up by themselves. This way, we increase the repeatability as the AI agent always follows the same set of steps.

Example for adding a new repository:

How to Add a New Repository

  Phase 1: Domain Model & Database

  1. Domain Model (src/{domain}/models/user.py)                                                                                                                                                                                                                     

  from dataclasses import dataclass                                                                                                                                                                                                                                 
  import datetime

  @dataclass
  class User:
      id: int | None
      email: str
      created_at: datetime.datetime

  2. Database Model (src/{domain}/db/models_db.py)

  from sqlalchemy import Column, BigInteger, String, DateTime, Index
  from db.base import Base

  class UserRow(Base):
      __tablename__ = "users"                                                                                                                                                                                                                                       
      id = Column(BigInteger, primary_key=True, autoincrement=True)
      email = Column(String, nullable=False, unique=True)
      created_at = Column(DateTime, nullable=False)                                                                                                                                                                                                                 

      __table_args__ = (                                                                                                                                                                                                                                            
          Index("ix_users_email", "email"),
      )                                                                                                                                                                                                                                                             

  3. Database Migration                                                                                                                                                                                                                                             

  alembic revision --autogenerate -m "Add users table"

  Use postgresql_concurrently=True for index creation in the migration.                                                                                                                                                                                             

  Phase 2: Repository Interface & Implementations                                                                                                                                                                                                                   

  4. Repository (src/{domain}/repositories/user_repository.py)

  from abc import ABC, abstractmethod

  class IUserRepository(ABC):                                                                                                                                                                                                                                       
      @abstractmethod
      def create(self, user: User) -> User: ...                                                                                                                                                                                                                     

      @abstractmethod
      def get_by_id(self, user_id: int) -> User | None: ...

      @abstractmethod                                                                                                                                                                                                                                               
      def get_by_email(self, email: str) -> User | None: ...

      @abstractmethod
      def list_all(self) -> list[User]: ...


  class UserRepositoryInMemory(IUserRepository):
      def __init__(self) -> None:
          self._users: list[User] = []                                                                                                                                                                                                                              
          self._next_id = 1

      def create(self, user: User) -> User:
          user.id = self._next_id
          self._next_id += 1                                                                                                                                                                                                                                        
          self._users.append(user)
          return user                                                                                                                                                                                                                                               

      def get_by_id(self, user_id: int) -> User | None:
          return next((u for u in self._users if u.id == user_id), None)

      def get_by_email(self, email: str) -> User | None:
          return next((u for u in self._users if u.email == email), None)                                                                                                                                                                                           

      def list_all(self) -> list[User]:
          return self._users                                                                                                                                                                                                                                        


  class UserRepositoryPostgres(IUserRepository):
      def __init__(self, *, database_session: Session) -> None:
          self._session = database_session                                                                                                                                                                                                                          

      def create(self, user: User) -> User:                                                                                                                                                                                                                         
          row = self._row_from_model(user)
          self._session.add(row)                                                                                                                                                                                                                                    
          self._session.flush()
          user.id = row.id                                                                                                                                                                                                                                          
          return user

      def get_by_id(self, user_id: int) -> User | None:                                                                                                                                                                                                             
          row = self._session.query(UserRow).filter(UserRow.id == user_id).first()
          return self._model_from_row(row) if row else None                                                                                                                                                                                                         

      def get_by_email(self, email: str) -> User | None:                                                                                                                                                                                                            
          row = self._session.query(UserRow).filter(UserRow.email == email).first()
          return self._model_from_row(row) if row else None                                                                                                                                                                                                         

      def list_all(self) -> list[User]:                                                                                                                                                                                                                             
          rows = self._session.query(UserRow).order_by(UserRow.created_at.desc()).all()
          return [self._model_from_row(r) for r in rows]                                                                                                                                                                                                            

      @staticmethod                                                                                                                                                                                                                                                 
      def _model_from_row(row: UserRow) -> User:
          return User(id=row.id, email=row.email, created_at=row.created_at)                                                                                                                                                                                        

      @staticmethod
      def _row_from_model(model: User) -> UserRow:                                                                                                                                                                                                                  
          return UserRow(id=model.id, email=model.email, created_at=model.created_at)

  Phase 3: Tests                                                                                                                                                                                                                                                    

  5. Test Fixture (tests/conftest.py)                                                                                                                                                                                                                               

  @pytest.fixture
  def create_user() -> Callable[..., User]:
      def _create(**kwargs: Any) -> User:
          return User(
              id=kwargs.get("id"),
              email=kwargs.get("email", "default@example.com"),                                                                                                                                                                                                     
              created_at=kwargs.get("created_at", datetime.datetime(2025, 9, 6, 10, 0, 0)),
          )                                                                                                                                                                                                                                                         
      return _create

  6. Contract Tests (tests/test_io/test_{domain}/test_repositories/test_user_repository.py)

  class UserRepositoryContract:
      @pytest.fixture
      def repository(self) -> IUserRepository:
          raise NotImplementedError                                                                                                                                                                                                                                 

      def test_get_returns_none_when_empty(self, repository):                                                                                                                                                                                                       
          assert repository.get_by_id(user_id=999) is None

      def test_create_and_retrieve(self, repository, create_user):                                                                                                                                                                                                  
          user = create_user()
          created = repository.create(user)                                                                                                                                                                                                                         
          assert created.id is not None
          retrieved = repository.get_by_id(created.id)
          assert retrieved is not None
          assert retrieved.email == user.email

      def test_get_by_email(self, repository, create_user):
          user = create_user(email="test@example.com")                                                                                                                                                                                                              
          repository.create(user)
          retrieved = repository.get_by_email("test@example.com")
          assert retrieved is not None                                                                                                                                                                                                                              
          assert retrieved.email == "test@example.com"

      def test_list_all(self, repository, create_user):
          repository.create(create_user(email="a@example.com"))
          repository.create(create_user(email="b@example.com"))                                                                                                                                                                                                     
          assert len(repository.list_all()) == 2


  class TestUserRepositoryInMemory(UserRepositoryContract):                                                                                                                                                                                                         
      @pytest.fixture
      def repository(self) -> IUserRepository:
          return UserRepositoryInMemory()


  class TestUserRepositoryPostgres(UserRepositoryContract):
      @pytest.fixture
      def repository(self, database_session) -> IUserRepository:                                                                                                                                                                                                    
          return UserRepositoryPostgres(database_session=database_session)

  Phase 4: Quality Checks

  make cq      # Formatting and linting
  make ut      # Unit tests                                                                                                                                                                                                                                         
  make it      # Integration tests

2. Use a different model for writing vs. reviewing the code

AI code review can be very powerful as described in this post. Anyhow, you'll experience much better results when you use two different models. Similar to human review. The author is less likely to spot the problem due to creator bias. So if you used Opus for coding, use Sonnet for review. For example:

Review this PR for bugs, security issues, and missed edge cases.
Focus on behavior changes, not style.

3. Point to code that does something similar

Often, what you're adding is very similar to something that already exists. For example, your app already supports Google login, and now you want to support GitHub login as well. Let the AI agent know about that when writing a prompt. Prompt example:

Add GitHub login support. Follow the same pattern as the existing Google login:
- OAuth provider: src/auth/providers/google.py
- Auth route: src/auth/routes/google_login.py
- Tests: tests/test_auth/test_google_login.py

Use the same callback flow, token exchange, and user upsert logic.
The GitHub OAuth scopes should be "user:email" and "read:user".

4. Be specific about the behavior

Many times, things are not implemented by AI agents as we never prompt them. For example, we only request to Implement a job for sending Welcome email with Postmark. This might already produce a useful result, but being more specific helps to achieve what we want in the first shot. Ask yourself: - When should X happen? - What if there's no user? - What if there's a retry? - What if the API is down? - What if the job is running twice?

Once you know the answers, specify that. For example:

Implement a job to send a welcome email using Postmark.
- It should be triggered at the end of the signup endpoint
- If the user doesn't exist, we should just early exit
- Don't ever retry the job to avoid double sending

5. Shape specification

Sometimes you have only a very high-level idea for a certain feature. In such cases, you should leverage an AI agent to help you shape it. Ask AI agent things like: - Is any information missing? - Do you need more details? - What happens with X if Y? - Do we need to consider race conditions? - Is performance relevant here?

For example:

**You:** I want to add a webhook system so external services can subscribe to events in our app. What do I need to think about before implementing this?

**AI:** A few things to clarify: What events should trigger webhooks - just user-facing actions like "order.created" or also internal ones like "cache.invalidated"? And should subscribers register via API or through a UI?

**You:** Only user-facing events. Registration via API.

**AI:** Got it. What about failed deliveries? If the subscriber's endpoint is down, should we retry? If so, how many times and with what backoff?

**You:** Yes, retry 3 times with exponential backoff. After that, mark it as failed and move on.

**AI:** What about duplicate deliveries? Network issues can cause the same event to be delivered twice. Should we add an idempotency key so subscribers can deduplicate on their end?

**You:** Good point, yes. Include an event ID they can use for deduplication.

**AI:** One more thing - authentication. Should subscribers provide a secret when registering so we can sign payloads with HMAC? That way, they can verify the webhook is genuinely from us.

**You:** Yes, HMAC signing with a shared secret. What about rate limiting? I don't want a single subscriber to overwhelm us with registrations.

**AI:** You could cap webhook registrations per account - say 10 active subscriptions. For delivery, you're already retrying with backoff, which naturally throttles. But you might also want a circuit breaker: if a subscriber's endpoint fails 10 times in a row, auto-disable it and notify them.

**You:** Good, let's do both.

Now you have a clear spec shaped through conversation. You can write a specific prompt based on that.

Become a better engineer, one article at a time.

Practices, mindsets, and habits that actually move the needle. Delivered weekly to your inbox.

Conclusion

In this article, we looked at 5 things you can do to improve code generated by AI agents. You might already know some of them, but I hope you learned at least something new from reading this. Try them out and let me know on Twitter or LinkedIn how it goes.

Happy vibing!

Share