I see many junior developers struggling to land their first role right now. AI is effectively doing the job of a junior developer. It churns out boilerplate, basic CRUD operations, and standard algorithms faster than any human can type. However, if you look at the job boards, there are still plenty of software engineering openings.
The industry has a new problem: AI has flooded codebases with a lot of crappy, unoptimized code that must be fixed. Companies are now looking specifically for senior engineers because they need people to clean up the mess that automated tools leave behind. If you are a mid-level developer who wants to stand out and secure your position, you must be demonstrably better than the AI.
The Danger of Copy-Paste AI Development
Let’s look at a practical case I dealt with recently. I had an AWS SQS which receives events from the changes in the order status.
The problem, of course, is that the events don’t arrive in the correct order. So my basket goes from bought, to payment pending, to draft and finally to delivered. You can imagine the face of the customer when receiving a notification that he must validate the payment of the basket to continue (the basket that he already paid yesterday). Another problem was that I have many consumers, so enforcing the correct order of the events is not always applied, as consumer 1 may not see the events consumed by consumer 2.
What’s the solution? Ask Claude Code for a fix. Alright, here is the fix it proposed: create a race condition at the write operation, that checks for the lock in the Postgres database to see if other consumers have already updated the status.
What was the reaction of the mid-level developer? It seems complex, it must be fine. Go ahead.
He didn’t even try to understand if that solution fits with our application. He didn’t even investigate some other alternatives. We see later, that the output of Claude Code suggested a better solution, adding a deduplication Id to the AWS SQS, but rejected it as no infrastructure information was given in the context.
How to Use AI as an Architect, Not a Coder
If you want to advance in your career, stop using AI to write your code outright. Instead, use the AI to help you find the solution. Do not ask for the final implementation; try to first understand the problem, the root cause, and the architectural alternatives.
You must be the one to choose the solution, not the AI.
When you dictate the approach, the AI merely acts as an advanced typewriter. In this second scenario, you did all the engineering work, and the AI simply wrote down a solution that you accepted, understood, and chose. Because you understand the implementation details and the trade-offs, you are fully equipped to investigate and patch the system when it inevitably breaks.
How Senior Engineers Catch AI Defects in Java Codebases
Let’s come back to our problem. Claude Code generated me some code that check the locks in the Postgres database.
public void processWebhookWithLock(Event event, EventBody eventBody) { transactionTemplate.executeWithoutResult(status -> { try { jdbcTemplate.execute( "SELECT pg_advisory_xact_lock(hashtext(?))", (java.sql.PreparedStatement ps) -> { ps.setString(1, eventBody.getBillNo()); ps.execute(); return null; } ); processDeliveryWebhook(event, eventBody); } catch (Exception e) { status.setRollbackOnly(); throw e; } }); }
The AI lacks infrastructure context. It doesn’t know that our architecture guidelines forbid raw SQL queries and manual transaction management in this layer.
As a professional, you should dictate the architecture. Knowing the first option is not always the best one. Checking in the AI output, we quickly saw the second option: modifying the AWS SQS to accept a deduplication Id to ensure no other consumer will receive events for the same order.
Instead, changing the way the messages are published to AWS SQS and using AWS SQS Fifo queues, solves all the problems. And nothing is needed in the consumers.
public SendMessageResponse sendDomainEvent(String messageBody, String partitionKeyId, DomainEvent domainEvent) { SendMessageRequest request = SendMessageRequest.builder() .queueUrl(queueUrl) .messageBody(messageBody) .messageGroupId(partitionKeyId) .messageDeduplicationId(domainEvent.getId()) .build(); return sqsClient.sendMessage(request); }
You defined the business rules and the structural pattern. You own the execution. If a null reference exception occurs in this transport layer, you know exactly where to look.
Actionable Takeaways for Mid-Level Developers
- Stop asking for final code. Ask for explanations of concepts, root causes, or architectural patterns.
- Own the implementation. If you cannot explain every line of the code to a peer, it should not go into production.
- Focus on diagnostics. Your value as a developer is now heavily weighted toward debugging and system design, not syntax generation.


Leave a comment