Transcription
Hi everyone. Today we're going to take a look at how we can use prompt-driven development to refactor an existing codebase. We'll start things off by taking a look at what the project is, how it works, how it's structured. Then we will gain an understanding of what we're trying to accomplish and how we would accomplish it. And then we'll get into prompting to actually do the refactoring. Be sure to take a look at all the resources, including the code for this demo in the description. And with all that being said, let's dive right in.
The first step to using any AI tool to accomplish any AI task is to have a good understanding of what you are trying to accomplish and how you would approach it. So, first up, let's first, you know, run the actual API that I have here. It's a pretty straightforward inventory API. It's built on Azure Functions Flex Consumption, FastAPI, Python, and Cosmos NoSQL API, and it allows us to create products, delete products, get the category of products, and things like that that you would expect in an inventory API. I actually have it open in the browser here. I'm just going to refresh this and just show you a little bit of the functionality.
I am first going to execute this get categories and hit try it out. Then I'll hit execute. Oh, API key required. Okay, because this is running locally, I can just use any key for the API key. We'll hit execute and take a look at the categories that we have available. Electronics. I'm just going to copy this and then cancel and minimize this. And then I'm going to select get products by category. Try it out. We already have electronics as default. So I'm going to just go ahead and run this. Oops. And it looks like we have one product in there with, uh, 50 of the wireless noise-canceling headphones. Right. So you get the idea of how this works. And then we have endpoints to add a new product, delete an existing product, and then we also have batch functionality. Okay.
Now, if we go back here, I'm actually going to stop this here. And I'm going to give us a little bit more space here in our file explorer. I'm going to delete this terminal here. And we can look under the inventory API directory. And we have a CRUD directory, models directory, and a routes directory. In our models, we have Pydantic models for our product. In the routes, we have all of our API endpoints, right? As you can see here, for example. And then what we want to focus on for this video is our CRUD directory. In our CRUD directory, I'm going to open up product_crud and product_batch_crud. And this layer is meant to interact with our database. So adding things to the database, removing, etc. But at the moment, it's doing more than that. As an example, if we take a look at the async def create_product, we see that it is doing some normalization, some conversion, and there's a whole bunch here of like exception handling, stuff like that. And a lot of this functionality should actually be in a service layer. So that's the refactor we want to focus on today.
Before we move forward with any prompting, I'm going to just show you my GitHub directory. And in here, I have a copilot-instructions.md file. And I highly recommend you take some time to outline what instructions you want to put in here for your own projects. This information gets sent along as context with every interaction that you have in GitHub Copilot Chat. So you want to strike a balance between having the absolute necessity but nothing extra because of course, you know, token consumption and whatnot. And there is such a thing as providing too much context and too much information to an interaction with an LLM as well. So here I'm keeping a couple things: some Azure Functions requirements, for example, stateless design, resource optimization. Additionally, I have some code standards here, and I am using dependency injection. And you'll most likely see this in some of the chat responses, so we'll call it out when it, uh, comes up. And data models, we're using Pydantic, client initialization patterns, and then Azure tools. And then additionally, I'm saying here to debug code, let's make sure we're using the `func start` task that is outlined in this file. And I find using things like this very helpful because you don't have to repeat it in your prompts, and it overall helps you get better responses out of your LLM.
Okay, now let's go ahead and start prompting. All right, so I've closed everything to give us a little bit more space. I am going to go ahead and, you know, try prompting. I'm going to select in the command palette, chat, new prompt file, and I'm going to use the prompts directory in the GitHub directory and I'm going to call this refactor CRUD layer. Perfect. And we want this to run in Azure mode. I have GitHub Copilot Chat open here. Azure mode is selected, and we'll use miniGPT-5 mini. I've not worked with that, uh, model yet. So let's see how it goes. So, I do want this to be set to engine mode. Awesome. And then I'm just going to start dictating here.
I need to refactor the CRUD layer. Look at all the files in the CRUD directory. Understand how they work. Understand how they work with the files in the routes directory and in the models directory and with the exceptions.py file. Okay, so that's first, kind of getting it to analyze. So I need to refactor the CRUD layer. Look at all the files in the CRUD use CRUD directory. CRUD. If you didn't know, the pound is simple as how you can add context. So that's why I'm adding it here to our prompt file. Understand how they work. Understand how they work with the files in the route. And again, we'll just route, which would be, uh, it's called routes actually, routes directory. The files in here and rest directory and in the models models directory and with the file just exceptions.py.
Okay, in the CRUD directory, we have product_crud.py and product_batch_crud.py. In these files, you will find a mix of code that implements things that should be in the CRUD layer that should remain in this file and functionality/code that should be moved to a new service directory and respective service files. Okay, so that's kind of once it understands what it needs to do, I want it to know where it should be, uh, putting this stuff, right? So say in the CRUD directory again, in the CRUD directory, we have product_batch.py. Okay, it missed the product product_crud.py and product_batch_crud. These files you will find a mix of code that implements things that should be in the CRUD layer. Things that, okay, uh, use mix of code that implements functionality that should remain in this CRUD layer and and functionality/code that should be moved to a new service directory in respective service files. We'll say we'll just call this product service and perfect. Great. What else can I would want? Let me take a look at this. Uh, we have product cosmos serialization. Okay. So here in our product_crud and our product_batch_crud files, we want only the code that directly interacts with the database to remain. Any other type of helper functionality and or business logic should be moved to the service layer. Again, just kind of reiterating so it understands what it needs to do. In our product product_crud.py and product underscore batch dot or underscore there we go pi files. We want only the code that directly interacts the database to remain. Any other type of helper functionality under business log.
Okay, let's say keep in mind any issues that you can see in the pound problems area and address them. Keep in mind any issues that you see in the pound problems area and address them before you consider the refactor factoring is during done. Okay. Uh, okay, cool. I think as far as the refactor, we can go ahead and leverage this. So, I'm just going to make sure this file is being saved. Save. And I'm going to close this. And I'm going to go ahead and do forward slash. And we should see our refactor CRUD layer prompt here. And I'm going to go ahead and send this here. I'm going to drag this out a little here. And we should see different files being edited and added and directories being created and things like that.
Okay, I like this to-do list UI element that we have now. Before, the only way that you would keep up with the work is just, you know, scrolling and seeing what was being outputted. Now we have sort of this task here that I really enjoy. Uh, so first, it's going ahead and reading everything that it needs to read. Great. Uh, it's going to analyze code, create service files, refactor code files, update routes, run checks. Okay, cool. That's actually exactly what the way that we would handle this task, right? Except it would probably take us longer to do so. All right, so let's give it a few moments. Let's see. All right, let's look like it's, uh, chugging along. Checkpoint. Oh, I like that. It tells us kind of when it sort of feels like it accomplished something, I guess. Checkpoint. I've read all CRUD models, exceptions, and route files. I'll update the to-do list mark. Okay, nice. Then I'll implement service layer by moving business logic from CRUD files, leaving database IO and CRUD. Okay, great. Let's see. Has it created anything yet? Not yet. Scroll down here. Next, I'll create services product service.py and services product batch. Okay, it will contain logic currently in CRUD that isn't directly DB calls. Great.
Okay, looks like something just happened over here. Awesome. Okay, so far nothing has surprised me, which is good. I always say that when you're using any kind of agent tool, in my opinion, it shouldn't be a very passive activity. Uh, I know people envision that's like potentially the future or where these tools are at right now. I don't think so. I think it's very easy to catch what these things are doing wrong if you are more involved in seeing the work as it goes. Right. So, for example, it has now made some changes to our product CRUD. I expect a lot of code to be removed from here. Yes, like all this, you know, validation business logic. That looks good. Additionally, it created the services directory, but no files in there quite yet. So let's go on here.
Next, I'll add the two service files properly. I previously failed to create file due to missing directory. It's now created. Okay, I guess that's what the original issue was. Open product service. And yes, a lot of this, yeah, it's been moved into this file. Awesome. That looks good so far. And we now it's created our our batch service as well. Okay, let's see all. Oh, you know what? I should also open this up here because we can look at our problems. And here we have a mix of like Pylance, Ruff errors as well. So I like to kind of keep this open because you get to see the number, right? You have 15 total problems, and then it, you know, increased to 21, and by the end, it should be at zero because I specifically told it to be at zero before it considers the refactor successful.
All right, let's keep taking a look at what's going on here. Uh, I'll add a small wrapper function to post item batching. Okay, that looks good. This batch group related edits to key. Okay, now I need to fix early. Okay, now it's working through linting things. All right. All right. It's keeping working through that. And so far, there's nothing that's making me feel like, oh, we need to stop this right now. It's going terribly, terribly wrong. It's just going to create a bunch of code that's not correct. So far so good. So, thumbs up to that. I'm going to open our product_batch service and take a look. All right, I'm guessing this has not been created correctly yet in the CRUD. So, uh, this is probably why we're getting an error here. Ah, there's indentation errors, too. Okay. All right. Starting to see these linting, uh, problems going down, or I guess general problems. They're not all, uh, lint related, though. Oh, I think now they kind of are not here. We have some more here. Let's open product service or product service and take a look at how it's going to be addressing these. Now, I'm going to move this over just a little to see if we can get a little bit more space here. Understand what's going on. All right, scroll down here. Okay, this is not correctly formatted. So, I I'm pretty sure it's going to be able to to resolve this, but that's why we're getting that error. Like, you could just visibly see the the issue here. I'm not going to mess with it. I'm going to let it go and try and figure it out. But, I think it's finished creating and editing or updating what it's needed to. Now, it just needs to go ahead and fix the Yeah, here went and fixed that annotation issue. Now has a bunch of unport unimp imported but unused things, which I'm assuming it can go ahead and also fix pretty easily.
Let's go to our product CRUD. Product CRUD. Product CRUD. Here we go. And it did not address all of the I guess I I I guess I did tell it to fix issues. And these aren't errors necessarily. It's summarizing everything to avoid circular imports. Services call CRUD modules which are lower level. Routes call services. Okay, correct. All right. So it looks like it has addressed everything that I've asked, which because we have no red errors here, I think that is correct. Let's take a look at these. I'm going to look at our product CRUD. All right. We'll move this over. Move this over here. I'll also move this over here. And yeah, it didn't remove the unused things, but I can actually do that pretty easily. Actually, you know what? I'm going to There are still some things in the problems area. I believe a lot of them are just import not errors but things that we can clean up. Take a look at them. There are some things in the and then we'll just do problems area just are just import errors, import, uh, messages, not errors, but things that we can clean up. Take a look at them.
Okay. Now, yes, we could just click on this and say remove unused imports, but that's the whole goal of agent prompt programming, right? Like to be able to flex our context engineering skills. Uh, so it should be able to. So, it does check workspace. Nine problems found in product CRUD. And this should be relatively easy. Okay. Just needs to remove the things that we are not using. Okay, I think it did it. Awesome. I personally believe that models are just going to get better and better at this. So, you might try this in like three months, and it's not even an issue. Uh, it just knows to to check for linting errors, right? I guess linting in Python is kind of difficult because like you can have your like if I go to my settings, settings, where's Y? Okay, here. And then I go into like, um, what is it? Pylance. Pylance. And you can have like different levels of linting or what is it? Ruff, maybe. Like there's, uh, like the strict level. I forgot where exactly that is, but the strictness, basic, I think it's set to there's a very, there's a specific thing. I can't remember exactly where it is. Uh, maybe it is in Intellis. [Music] No, but anyway, you can set the different levels of linting strictness, I guess, and stuff like that. I quite like the way that these things are looking. This does have the business logic that was before in the CRUD layer. Uh, so, oh, you know what? I should take a look at our routes. How did they change? Perfect. This looks good here. Yeah, not working directly with the CRUD. Instead, working with the service. Okay, cool.
So, I'm gonna hit keep. And what we can do is now simply do a very, uh, I guess just run. Let's run the function. Move this over here and basically try to make sure it works. We're going to refresh this here. Authorize and close this here. Get categories, try it out. Execute. And this is like manual testing, right? I could probably try getting GitHub Copilot to test things out. Okay, let's get products by category. Actually, let's, yeah. Uh, execute this. Okay, let's say the function is currently running. Can you try to add a product, update a product, and delete a product? Okay, let's see. It should be able to do some terminal commands to try this. And since it knows the type of payload because it has access to the models, it, uh, shouldn't have any issues. I'll create a short to-do list for the three actions. I'll create, update, delete. All right. Detail not found. It's not. I don't think it's calling the right one. I'll run three HTTP calls using K. All right, let's see. I'll inspect the function hosting. All right. I think it may not know which. Oh, no. I found it. It found the right endpoint. Okay, cool. Oh, no. Did it not create 60 capture ID tag for next step? I'll parse them and then issue a patch to update. All right, there. Okay, looks like it is work. Let's move this up here. Let's move this over here. All right, I create, update, and delete your project against here running function host and verified responses. And I guess we can go and kind of execute this once more. Oh, no. Uh, execute the categories. We still have electronics. Whoops. Created updated categories test key. And then it deleted it. So it's hard to tell. Let's try let's try one more thing. We'll say, um, now just try adding a product. And I feel like it should be better at understanding which endpoints they use, but I think that's something that I could clarify better in the Copilot instructions.
All right, scroll down here. Done. Quick add product ad. If I go here, I wonder if I created it in the electronics category. No, let's go here. It's in the gadgets category. Okay, in the gadgets category, there is now a quick product. All right, so that's enough of us playing around here. I would consider this refactor at least 80% done. And it took us what, like 20 minutes to get that going? And then from there, the rest of the work is on us as, you know, the software developers or whatever you want to call yourself, in terms of, you know, having tests, looking through the code, verifying. It's kind of just like any other, uh, PR that you could consider. There's a lot of things that you have to check before, uh, you can ship to prod, right? Uh, but yeah, that's that's it for this example, and that is it for this video. We took a look at how we can use prompt files to refactor, uh, what we needed to refactor in this codebase. We understood a little bit of how we can leverage Copilot instructions to outline best practices and any information that we need specific to our codebase. Additionally, we saw how we can leverage the problems context and other types of contexts to improve our prompts to be able to accomplish a refactor. Be sure to check out all the resources linked in the description. If you have any questions, drop them in the comments, and I'll see you in the next video.