DEV Community

Cover image for What I Actually Learn When I Build With AI
Jessica Doering
Jessica Doering Subscriber

Posted on

What I Actually Learn When I Build With AI

Tests help retain code lessons

I've spent entire nights building something with AI, gotten a bunch of features working, and then realized I couldn't really explain half of what I'd just built.

And then there are nights when I spend hours trying to figure out one stupid little problem, and somehow end up learning more from that than I did from the entire night before.

It's kind of funny when you think about it. Both times I was productive. Both times I ended up with working code. But what I actually learned from each experience was completely different.

I wrote a post recently about how AI is making it way too easy to avoid thinking, and it got me thinking about my own habits. Because I use AI coding tools constantly. I love them. They've helped me build things I probably wouldn't have even attempted otherwise.

But I'm also still learning. A lot.

And there is a big difference between just getting something working and actually understanding how it works.

Just because I understand the explanation doesn't mean I understand the code

This probably happens to all of us more than we'd like to admit.

I might ask AI to explain something, and it'll give me a perfectly reasonable breakdown. Everything makes sense. I can follow along, I understand what each part is doing, and I think, okay, got it.

Then 3 days later I need to change something, and suddenly I'm staring at the code like I've never seen it before.

Apparently, I understood it just fine when someone was holding my hand through the entire explanation.

That is not quite the same thing as actually knowing it, though.

And I'm not talking about memorizing syntax or remembering every little API detail. I look things up all the time, and I don't see anything wrong with that.

I'm talking about understanding why something was done a certain way.

If all I can remember about a feature is that AI wrote it and it worked, I haven't really learned much from it.

Sometimes the interesting part is the problem you didn't know existed

I've been working on a text editor called Slate, which has been a really interesting learning experience for me.

One thing I hadn't given much thought to before was what actually happens when you save a file while you're still editing it.

I mean, saving a file sounds pretty simple, right? Write the contents to disk, mark it as saved, done.

Except what happens if the user keeps typing while that save is happening?

The file being written contains the older content, but the editor now has newer changes. So if the save finishes and the editor clears the unsaved indicator, it's basically telling the user everything is saved when it isn't.

Slate uses revision-based save tracking to handle this. When a save starts, it remembers which revision of the document it's saving. That way, any changes made while the save is happening don't accidentally get marked as saved too.

Now, AI could have just implemented all of that for me. I could have tested the save button, seen that it worked, and moved on with my life.

But understanding why that revision tracking matters is what makes it useful to me.

It's not really about the code itself. It's about recognizing that something can change between the time an operation starts and the time it finishes.

And that's a problem that could come up in all kinds of applications, not just text editors.

That's the kind of thing I want to take away from a project.

Actually experimenting makes a huge difference

I've noticed the same thing when working with local AI models.

Let's say I run a model and it takes 30 seconds to complete something.

Okay, so it's slow. Right?

Well, maybe. But what actually took 30 seconds?

Was most of that time spent loading the model into memory? Was the actual processing slow? Would running it a second time be significantly faster?

Those are all things I can test.

And I find that I learn a lot more when I actually start experimenting instead of just asking AI to explain what's happening.

Run it again. Measure things separately. Change something. See what happens.

Sometimes the results are exactly what I expected. Other times they're not even close, which is usually when things get interesting.

I love that I can use AI to help me figure things out. I can ask what else I should try, or why the result isn't what I expected.

That makes learning unfamiliar things so much easier.

But there's a big difference between AI telling me why something should happen and me actually seeing what does happen.

And sometimes AI's explanation is wrong, too. Which I am sure we all know.

I don't necessarily remember the code, but I remember the problem

I think this is probably the biggest thing I've noticed.

When I really spend time understanding something, I might not remember the exact implementation later. But I remember the problem I was trying to solve and why I solved it that way.

And that carries over into other projects.

Maybe I start wondering whether some asynchronous operation could finish after the user has already changed something.

Or whether a performance issue is actually a startup issue.

Or whether I'm storing some piece of state that I could just calculate from something else.

I might still need to look things up. I might still ask AI to help me write the implementation.

But at least I know what I'm looking for and why it matters.

If I just accept the generated code without thinking much about it, I miss all of that. The solution is sitting right there in my project, but I might not even recognize the same problem when I run into it somewhere else.

And considering how often I start new projects, there's a pretty good chance I will run into it somewhere else. Probably next week.

Of course, I don't need to turn everything into a learning experience

I also think there's a balance here.

Sometimes I just want AI to fix the padding on a button.

I don't need to spend 45 minutes investigating the underlying principles of CSS spacing. I just want the button to look right.

And there are plenty of things I'm perfectly happy to let AI handle. Boilerplate, repetitive changes, things I've already done a hundred times, or just tedious work I don't feel like doing.

That's part of why I use these tools in the first place.

But when I'm building something unfamiliar, or working on functionality that I know I'll need to maintain later, I try to be a little more involved.

Sometimes that means just asking questions.

Other times I might just start changing things to see what happens.

I think even something as simple as predicting what a change will do before running it can make a difference. Because if the result isn't what I expected, now I have something to investigate.

Do I do this every time? Absolutely not.

Sometimes I've been staring at something for two hours, AI finally gets it working, and my entire thought process is basically "thank you, finally, moving on."

I'm not going to pretend otherwise.

But I am trying to be more conscious of when I'm actually learning something and when I'm just getting something done.

Because those aren't always the same thing.

Getting something working isn't the same as learning how it works

One of my favorite things about AI coding tools is how much more willing I am to try things I know very little about.

I've experimented with languages, frameworks, local models, desktop applications, and all kinds of other things that I probably would have put off before.

Not necessarily because I couldn't learn them, but because getting started on something completely unfamiliar can be a lot of work.

AI makes that initial hurdle so much smaller, and I think that's genuinely awesome.

But there's also a temptation to just keep building. One feature works, so you move on to the next one. Then the next. Before you know it, you've got a whole application and only a vague understanding of some pretty important parts of it.

And it's so easy to confuse all that progress with learning.

I've definitely done it.

I think the things that stick with me the most are usually the things I had to investigate a little. Something didn't behave the way I expected, or I got curious about why it worked a certain way, and I spent some time figuring it out.

Sometimes that investigation only takes a few minutes. Sometimes it sends me down a rabbit hole for the rest of the night.

Either way, I tend to remember those experiences a lot more than the features that worked perfectly on the first try.

And that's something I want to keep in mind as I continue building with AI.

I don't want to stop using these tools or intentionally make everything harder for myself.

I just don't want to get so caught up in how much I can build that I forget to pay attention to what I'm learning along the way.

So... what about you? Have you learned something useful while building with AI that you can now troubleshoot or explain yourself? Or have you ever gone back to AI-generated code and realized you had absolutely no idea how it worked?

Top comments (17)

Collapse
 
pierrelaurentmedori profile image
Pierre-Laurent Medori •

Your Slate example sent me to the repo, and the revision counter is right there in document.rs, pinned down by a test called edits_during_a_save_keep_the_document_dirty. A test is a nice way to remember the problem even after you've forgotten the code.

In the spirit of "the problem you didn't know existed", that same save path has one more: what's on disk if the app dies halfway through the write? write_text calls std::fs::write, which empties the file before writing, so a crash or power cut at the wrong moment leaves half a file. The funny part is that the fix is already in your repo: storage.rs has write_atomic (temp file, then rename) for the settings JSON. So right now your settings are better protected than your documents.

It's not a free swap for user files, though. Renaming over the original replaces it, so permissions, symlinks and hard links need care, and surviving a power cut also needs an fsync before the rename. That trade-off is why Vim has a whole option for it (backupcopy).

To answer your question: mine is a cousin of your save race. I once watched an API confirm a delete, then return the deleted item on the very next read. "The write succeeded" and "everyone can see it" turned out to be two different moments, and I've looked for that gap ever since.

Collapse
 
sizzlebop profile image
Jessica Doering •

Thank you so much for taking the time to actually dig through my repo. I genuinely appreciate comments like this. It’s one thing to have someone read a post, but when someone actually goes looking through the code and points out something I hadn’t considered, that’s incredibly valuable to me.

And you’re absolutely right, that’s another interesting edge case I hadn’t really thought about. Especially since I already have an atomic write implementation for the settings. Now you’ve given me something else to investigate.

I think that’s one of my favorite things about sharing projects publicly. I’m still learning, and getting feedback from people who take the time to actually understand what I’ve built is such a great part of that.

Also, your API delete example is a perfect example of what I was trying to get at in the post. It’s those little situations you run into that end up teaching you something you remember long after you’ve forgotten the actual code.

Collapse
 
pierrelaurentmedori profile image
Pierre-Laurent Medori •

Glad it was useful! Honestly, it works both ways. I'm always curious to see how other people tackle the problems I'm facing myself. It's enriching, and sometimes reassuring too, when someone else lands on the same idea I had.

Collapse
 
urion profile image
Matteo Poli •

The save example is a great one, because the lesson isn't the code, it's the shape: something can change between when an operation starts and when it finishes. Once you've seen it once you spot it everywhere, like a fetch that resolves after the user already navigated away, or a retry that lands after the first attempt succeeded.

What helps me with the "three days later I'm staring at it like I've never seen it" part: when I finally understand why a line is the way it is, I write that why down as a short note on that line, in my own words. Not the explanation the AI gave me, but the problem it solves. Next time I open the file the note is there. And if I can't write it, that's usually the sign I understood the explanation, not the code.

(Disclosure: I build Reado, an IDE where notes like that live on the lines, so I'm biased toward this habit.)

Collapse
 
sizzlebop profile image
Jessica Doering •

I really like that. Especially the part about writing down the problem the code solves rather than just explaining what the code does. I think that's such an important distinction, and honestly, something I should probably make more of a habit of doing myself.

And you're absolutely right about recognizing the same problems in completely different situations. That's exactly the kind of learning I was trying to get at with this post. Once you understand why something matters, you start noticing it in places you wouldn't have thought to look before.

Also, Reado sounds interesting. I love seeing the different approaches to problems like this, especially when they end up building their own tools to solve them. I can definitely relate to that part.

Collapse
 
urion profile image
Matteo Poli •

Thanks, Jessica. The "why" note pays off most months later, when whoever reads the code (often me) has forgotten the conversation that produced it. It's your point again: you remember the problem, so write the problem down right where the code is.

Collapse
 
build996 profile image
build996 •

Your point about predicting a change before running it suggests a useful follow-up a few days later: try a small variation without reopening the original explanation. With Slate, that might be asking what the unsaved indicator should show when two saves finish in the opposite order. Explaining the first example can lean on memory; predicting a variation asks whether the underlying model transfers. Would that feel like a useful learning check, or turn a hobby project into homework?

Collapse
 
sizzlebop profile image
Jessica Doering •

I actually really like that idea. I think being able to apply what you’ve learned to a slightly different situation is probably a much better test of whether you really understand something than just being able to explain the original example.

And I think it could be a useful learning check, as long as I’m not doing it for absolutely everything.

For me, a lot of the fun of building things is getting curious about something and going down those little rabbit holes. Sometimes I’ll spend hours figuring out something that probably could have been done in a few minutes, just because I want to understand it better.

But other times I just want to finish what I’m working on and move on.

I think the trick is knowing when something is worth digging into a little deeper. If it’s a concept I’m likely to run into again, especially something I didn’t understand before, then trying a variation a few days later sounds like a great way to see if anything actually stuck.

Thanks for the suggestion! I might have to give that a try.

Collapse
 
build996 profile image
build996 •

The 'not for absolutely everything' limit makes sense; otherwise a learning check becomes another obligation attached to finishing a project. I'd reserve it for a concept that changed a design decision or caused a bug, where forgetting has a real future cost. For a one-off formatting task, getting it done can be the whole goal. Your distinction between following curiosity and choosing to finish seems like a better guide than a fixed quota of exercises.

Collapse
 
n_c_e4a8149b59e51d8be77 profile image
N. C. •

“The solution is sitting right there in my project, but I might not even recognize the same problem” really captures the gap this post is exploring. The save-tracking example makes it concrete: remembering the implementation isn’t the same as knowing which question to ask when state changes during an operation. I especially appreciate that you don’t turn learning into a requirement to struggle through everything manually. The goal isn’t to earn every line of code—it’s to understand the decisions you’ll eventually have to revisit. Honest, practical, and refreshingly free of the usual “AI is cheating” versus “understanding no longer matters” extremes.

Collapse
 
sizzlebop profile image
Jessica Doering •

Thank you! I'm really glad that came across, because that's exactly what I was hoping to get at with this post.

I love building with AI, and I certainly don't think we need to struggle through every little thing just to prove we're learning something. But I also don't want to get so comfortable having things done for me that I stop asking questions or understanding the decisions being made.

And I agree, I think the conversation around AI and coding gets pushed into those two extremes way too often. There's a whole lot of middle ground where we can take advantage of these tools while still learning and improving as developers.

Collapse
 
pushpendra2011 profile image
Pushpendra Yadav •

The line about remembering the problem rather than the code really lands. Mine came from building a recommendation app with embeddings. Every item has an LLM-written description and a vector, and both carry a version number. That looks like over-engineering until you change the prompt or the embedding model and realise half your data was made one way and half another, with nothing in the rows telling you which. It’s a cousin of your save-revision problem: derived data quietly drifting from what produced it. Now, whenever I store something generated, my first question is “what made this, and how would I know if that changed?”

Collapse
 
sizzlebop profile image
Jessica Doering •

That's an excellent example. And I can see how versioning everything could be seen as overengineering at first until you change a model or your prompt and you don't have any clue of which data was generated with what.

I really like your point about asking "what made this, and how would I know if that changed?" That is a great way to look at things especially when working with AI-generated data where the underlying models and prompts can change over time.

That's exactly what I was getting at in my post. Once you've run into a problem like that and actually understand why it matters, you start recognizing similar situations in completely different projects.

Thanks for sharing. It's given me something else to keep in mind with my own projects.

Collapse
 
codingwithjiro profile image
Elmar Chavez •

"...I might not even recognize the same problem when I run into it somewhere else."

THIS! That's why I always build my new projects intentionally slow. Every time I touch a new framework or library or new area in my codebase, I often tend to learn the why's first. What problem it solves and whether I am overengineering it.

AI is helpful in this case since it searches up latest documentations easily and could give me links which I read for verification. If I'm still lost, AI would help me dumb it down so I could keep up.

It's also the same as with school. Sure, most of the students can nod along while the professor explains things but without reflection and practice, the lesson will not stick. Same reason why I try it myself first, explain the concepts with my own words and I would let AI find gaps in my understanding. That way, I am confident that when the same problem comes up, I would be able to step up and solve it on my own.

It doesn't matter if I forgot the exact implementation (that's what the internet is for). What's important is I know what answer I need. That's way different than just searching for the answer.

Collapse
 
sizzlebop profile image
Jessica Doering •

I love that last point about knowing what answer you need rather than just searching for one. I think that's such an important distinction, and it really sums up a lot of what I was trying to get at with this post.

I also really like your approach of trying to understand something yourself first and then using AI to find the gaps in your understanding. That's something I've been trying to get better at myself.

And I agree about the overengineering part, too. Sometimes when you're learning something new, it's hard to tell whether a particular approach is actually necessary or just adding complexity you don't need. Understanding why something exists in the first place makes those decisions a lot easier.

I don't always have the patience to take things slowly, especially when I'm excited about a new project and just want to build everything at once. But I definitely see the value in it.

Collapse
 
magopredator profile image
Fenix • • Edited

Caminante, son tus huellas
el camino y nada más;
Caminante, no hay camino,
se hace camino al andar.
Al andar se hace el camino,
y al volver la vista atrás
se ve la senda que nunca
se ha de volver a pisar.
Caminante no hay camino
sino estelas en la mar.

Todo pasa y todo queda
Pero lo nuestro es pasar
Pasar haciendo caminos
Caminos sobre la mar.

...es un extracto de un muy conocido poema de Antonio Machado.

Collapse
 
magopredator profile image
Fenix •

...nadie conoce cada esquina del mundo ni de la vida, y nadie sabe realmente hacia dónde va. ¡Y yo acabo de llegar! :) ...