My Rule for Using AI-Generated Code: I Must Be Able to Explain It Before I Ship It


 Sometimes you meet an error and you don’t even know where to start. That is one place AI can help. It can explain the documentation, suggest a query or help you put together a component. I use it to learn and move forward, but I still need to understand what it gives me.

I have already written about where AI helps me as a developer and where I still do not trust it. Here I want to explain what I check before I put that code into a product. Getting an answer is one thing. Knowing whether it belongs in your project takes more work.

An answer coming fast doesn’t mean the answer is correct.

You can look at the code and think, yes, this looks good. The names are correct and everything looks arranged. But it may still use an old API, miss a situation your users will face or change how your login works. Sometimes it solves another problem entirely.

For me, this is the rule I want to keep: if I cannot explain the important parts of the code, I am not ready to ship it.

I don’t have to cram every method. I can still check documentation. But I should know what goes into the function, what it changes, what comes back and what happens if something fails.

First, I explain what I actually need

If I only say “fix my app,” there is too much room for guessing. I need to explain the part that is failing and what I expect it to do.

These are the details worth writing down before asking:

  • the exact outcome I need;

  • the framework and version I am using;

  • where the code will run—browser, server or database;

  • the shape of the input and expected output;

  • authentication and permission requirements;

  • important failure cases.

Now I have something to compare the answer with. Did it do what I asked, or did it quietly change the plan?

I work on the part that needs fixing

When the whole project changes at once, checking it becomes another big job. A small change is easier to understand.

Take an upload problem. I would start with the validation or the storage request that is failing. I don’t need a new dashboard just because an image won’t upload. With a smaller change, I can check what worked before and what works now.

I also want to keep the parts that already work. A fix shouldn’t create fresh problems elsewhere.

I follow where the data goes

Before accepting a function, I ask myself:

  1. Where does the input come from?

  2. Is it trusted or controlled by a user?

  3. How is it validated?

  4. What database, API or file operation occurs?

  5. What is returned to the user?

  6. What happens when the operation fails?

If I get stuck on one of these questions, that is where I need to learn more before merging it.

A function can compile and still do the wrong thing. It might trust an account ID someone sends, expose private fields or mark an order as paid without verifying the payment. That is why I look beyond whether the editor shows an error.

I check the packages and documentation

A package name in an AI answer is still something to verify. It could be old, unnecessary or a package that doesn’t exist.

I go back to the official documentation and check the version in my project. I look at the function name, setup, where it can run and any security notes. Copying an example for another version can bring another error.

Then I ask whether I need that package at all. If a small function can handle the job, I don’t want to add a large dependency without a reason. Every package brings download size and something else to maintain.

I take more time with login, payments and user data

There are parts of a product where rushing can cost somebody more than a broken layout.

With login, permissions, payments, uploads and private data, looking correct is not enough for me. I need to check how the code behaves and who can use it.

These are the checks I keep in mind:

  • secrets remain on the server;

  • the server verifies the user's permission instead of trusting the interface;

  • database rules restrict access to the correct rows;

  • payment status is verified independently;

  • uploaded files are limited by type and size;

  • error messages do not expose private details;

  • repeated requests cannot create duplicate results.

I can ask AI to point out risks too. But I still have to verify the answer, and get another review when the change needs it.

I test what happens when things go wrong

Most examples show everything working. Your users will not always have that experience. A session can expire, a network can be slow and a provider can return an error.

So I check empty fields, wrong input, no session, slow responses and repeated clicks. For a feature that changes user data, testing with two accounts matters. One user should not be able to open or change the other user’s records.

In a test environment, I can also remove a value the code expects and see what happens. The user needs a message that helps them take the next step. They don’t need private details from the server.

I read what changed before accepting it

I read the diff, which shows the changes to the files. I look for checks that disappeared, new environment variables, configuration changes and edits that have nothing to do with the problem.

After that, I run the tests, linting and build checks the project has. If there is no automated test for that feature, I write down the manual checks so I know what I actually tested.

A build passing is useful, but I still need to try the feature. The build cannot tell me that every permission or payment decision is correct.

What I ask before shipping

Before shipping generated code, I ask:

  1. Can I explain what every important section does?

  2. Does it solve the exact task rather than a similar one?

  3. Did I verify the APIs in official documentation?

  4. Is user-controlled input validated?

  5. Are authentication and authorization checked on the server or database?

  6. Are secrets and private data protected?

  7. Did the change add an unnecessary dependency?

  8. Have I tested failure, retry and duplicate-request behaviour?

  9. Did I inspect the complete diff?

  10. Can I maintain this code when the AI conversation is gone?

I want AI to help me learn and build. I still have to take responsibility for what goes into the application.

If a suggestion saves me time, good. I should use some of that time to understand it, test it and check whether it fits.

I am still learning, and I want to keep improving. For me, progress means I can explain the code, check that it works and come back later to maintain it. Just having more code on the screen is not enough.

Post a Comment

Previous Post Next Post

Contact Form