Featured image of post AI-Assisted Development: What Actually Works and What's Hype

AI-Assisted Development: What Actually Works and What's Hype

I’ve been using AI coding assistants for 18 months now. Here’s what’s real and what’s theater.

When GitHub Copilot first landed in my editor, I was skeptical. Another “productivity tool” that would slow me down with bad suggestions? But after shipping hundreds of features in our SaaS transportation platform with AI assistance, I’ve formed strong opinions about where AI actually shines—and where it absolutely fails.

This is not a promotional piece. This is honest.

What AI is Genuinely Good At

1. Boilerplate and Repetitive Code

If you’re writing a CRUD endpoint for the nth time, AI will save you 15 minutes per endpoint. It doesn’t eliminate the work, but it removes the tedium.

Example: Entity Framework DbSet operations

I started typing:

1
2
3
4
5
6
7
8
public class ShipmentRepository : IShipmentRepository
{
    private readonly TransportDbContext _context;
    
    public ShipmentRepository(TransportDbContext context) => _context = context;
    
    public async Task<Shipment> GetByIdAsync(string id) =>
        await _context.Shipments.FirstOrDefaultAsync(s => s.Id == id);

Copilot finished:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    public async Task<IEnumerable<Shipment>> GetAllAsync() =>
        await _context.Shipments.ToListAsync();
    
    public async Task AddAsync(Shipment shipment)
    {
        await _context.Shipments.AddAsync(shipment);
        await _context.SaveChangesAsync();
    }
    
    public async Task UpdateAsync(Shipment shipment)
    {
        _context.Shipments.Update(shipment);
        await _context.SaveChangesAsync();
    }
    
    public async Task DeleteAsync(string id)
    {
        var shipment = await GetByIdAsync(id);
        if (shipment != null)
        {
            _context.Shipments.Remove(shipment);
            await _context.SaveChangesAsync();
        }
    }

Verdict: Saved me 5 minutes. I still reviewed every line.

2. Test Case Scaffolding

Writing test setup code is mind-numbing. AI is excellent at it.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
[TestFixture]
public class DeliveryServiceTests
{
    private Mock<IShipmentRepository> _shipmentRepoMock;
    private Mock<ICapacityService> _capacityServiceMock;
    private Mock<IBillingService> _billingServiceMock;
    private DeliveryService _service;
    
    [SetUp]
    public void Setup()
    {
        _shipmentRepoMock = new Mock<IShipmentRepository>();
        _capacityServiceMock = new Mock<ICapacityService>();
        _billingServiceMock = new Mock<IBillingService>();
        _service = new DeliveryService(
            _shipmentRepoMock.Object,
            _capacityServiceMock.Object,
            _billingServiceMock.Object);
    }

AI will complete the test methods, mock setup, and assertion patterns. Is it perfect? No. Do I have to fix things? Yes. But it’s a 40% time savings.

3. Documentation and Comments

Writing XML docs for 50 methods is torture. AI does this remarkably well:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/// <summary>
/// Calculates the optimal delivery route based on shipment weight,
/// distance, and current truck capacity.
/// </summary>
/// <param name="shipment">The shipment to route</param>
/// <returns>A list of route waypoints in order</returns>
/// <exception cref="InvalidOperationException">
/// Thrown when no feasible route exists
/// </exception>
public async Task<IEnumerable<RouteWaypoint>> CalculateOptimalRoute(Shipment shipment)

The AI’s context awareness of your codebase is strong here.

Where AI Falls Apart

1. Understanding Your Custom Patterns

This is the big one. Our transportation domain has custom patterns that Copilot doesn’t understand.

We have a custom idempotency pattern for OrderId generation:

1
2
3
4
5
public class IdempotentOrderCommand
{
    public string IdempotencyKey { get; set; }
    public DateTime IssuedAt { get; set; }
}

When I asked Copilot to “implement an idempotent command handler,” it wrote:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public async Task<OrderResult> HandleAsync(OrderCommand cmd)
{
    var existing = await _cache.GetAsync(cmd.IdempotencyKey);
    if (existing != null) return existing;
    
    // Process command
    var result = await ProcessOrder(cmd);
    
    // Cache for 24 hours
    await _cache.SetAsync(cmd.IdempotencyKey, result, TimeSpan.FromHours(24));
    return result;
}

That’s fine, but it missed our specific requirements:

  • We use the combined hash of IdempotencyKey + OrderId as the cache key
  • We have a fallback to database lookup if cache misses
  • We use a TTL that’s business-configurable, not hardcoded

The lesson: AI generates “general” solutions. Your code often needs “specific” solutions. You can’t just copy-paste.

2. Complex Multi-Service Flows

When I described a delivery booking flow across 5 services, Copilot generated code that:

  • Didn’t handle partial failures correctly
  • Ignored the compensating transaction pattern
  • Hardcoded timeouts
  • Had no retry logic

I had to completely rewrite it. It saved me nothing—it cost me time reviewing obviously wrong code.

3. Performance-Critical Code

Copilot has no concept of your performance constraints. A routing algorithm that works for 10 shipments but O(n²) for 10,000 shipments? Copilot will generate it confidently.

We have a spatial index lookup for nearby trucks:

1
2
3
// Copilot's suggestion:
var nearbyTrucks = _trucks.Where(t => 
    DistanceTo(t.Location, shipment.Pickup) < 10).ToList();

This is O(n) and runs on every request. The correct solution uses an R-tree spatial index. Copilot didn’t suggest it because it had no context that this list grows to 50k+ records daily.

4. Architecture Decisions

“Should we use Service Bus or Event Grid for this event?” I asked.

Copilot gave me a generic answer that was technically correct but didn’t account for:

  • Our need for message ordering (Service Bus)
  • Our high volume (Event Grid would be cheaper)
  • Our retry requirements (both work, but differently)

It did not know our constraints. An architect still had to decide.

The Honest Productivity Metrics

Over 18 months working with AI on our platform:

TaskTime SavedQuality Issue Rate
Boilerplate CRUD~40%5%
Test scaffolding~35%12%
Documentation~60%2%
Routing algorithms~10%45%
Configuration classes~45%8%
Business logic~5%60%
Database migrations~50%8%
API endpoint structure~30%15%

Average across the project: ~28% time savings, but only when used in the right context.

How to Use AI Coding Tools Effectively

  1. Use it for what it’s good at. Write the hard 20% yourself. Let AI handle the mechanical 80%.

  2. Maintain healthy skepticism. If AI writes something you don’t fully understand, don’t ship it. Rewrite it.

  3. Give it context. Comment your patterns. The more context files your AI tool has access to, the better it understands your domain.

  4. Don’t outsource thinking. Use AI to accelerate thinking, not replace it.

  5. Review ruthlessly. Every line of AI-generated code should be reviewed like a junior developer wrote it. Because in some ways, it did.

  6. Know its blind spots. Performance, security, and domain-specific logic are where AI struggles most. Pay extra attention here.

The Real Question

“Does AI make you a better developer faster?”

Yes, but only if you’re already a good developer. AI amplifies your ability to execute your ideas. It doesn’t help you come up with the ideas. If you don’t understand distributed systems, no amount of Copilot will help you design one.

In our platform, AI has been a force multiplier. We’ve shipped 3x more features per quarter than we would have otherwise. But every complex decision—architecture, performance, reliability—still required human engineers. And that’s how it should be.

The hype says AI is replacing developers. The reality? AI is replacing boring tasks, so we can focus on the interesting ones.


Use it. But stay skeptical. And always, always understand what your tools write.

All rights reserved
Built with Hugo
Theme Stack designed by Jimmy