Webbo3 Level 2 · JavaScript Development · Day 16 of 20
AI-Assisted Development
Using AI the way an engineer does: as a fast assistant you supervise, never as an authority you obey.
By the end of today you can
- Prompt for code with enough context to get something useful
- Review AI output the way you would review a stranger's pull request
- Spot a hallucinated method, a subtle logic error and an insecure pattern
- Use AI for the things it is genuinely good at, and stop using it for the rest
- Live by one rule: never submit code you cannot explain
Nobody is going to tell you not to use AI. You will use it, your colleagues use it, and pretending otherwise would make this course useless the day you leave it. What separates a developer from somebody typing prompts is not whether they use it. It is whether they can tell when it is wrong.
1. What it is actually good at
| Genuinely good at | Quietly bad at |
|---|---|
| Explaining an error message in plain English | Knowing whether your code is actually broken: it cannot see your screen |
| Generating practice material and test data | Judging what matters in your product: it does not know your users |
| Boilerplate you have written a hundred times | Anything depending on your codebase that you did not paste in |
| Reviewing your code as a hostile reader | Writing code for a library version it half-remembers |
| Expanding a list of edge cases you started | Producing the first list, which is where your judgement lives |
| Turning a rough README into a clear one | Deciding your architecture, which it will do confidently and badly |
The pattern across that whole table
AI is strong where the work is transformation, and weak where the work is judgement. Rewriting, explaining, expanding, translating: good. Deciding what matters, whether this is right, what to build: yours.
2. Prompting that gets something usable
write me a function to filter studentsYou will get a plausible function for a made-up data shape that does not match yours. Compare:
I am writing vanilla JavaScript, no frameworks, ES modules, for a browser.
Here is my actual data shape:
{ id: 12, name: "Chidinma Okafor", score: 88, city: "Lagos", paid: true }
I have an array of about 200 of these in `state.students`.
Write a function `visibleStudents(state)` that returns the students matching
BOTH `state.search` (case-insensitive, matches any part of the name) and
`state.filter` (one of "all", "paid", "unpaid").
Constraints:
- Do not mutate `state.students`
- Return an empty array when nothing matches, never null
- No libraries
Then list three edge cases your function does NOT handle.- The real data shape. Most bad output is AI guessing at a shape you never gave it.
- The constraints. Vanilla, no libraries, do not mutate. Otherwise it will reach for lodash and React.
- What "done" means. Empty array not null. Say it or you will get
nulland a crash three files away. - Ask what it did not handle. This last line is the highest-value sentence in the prompt: it forces the model to argue against its own output, and it is where you find out that empty search was never considered.
3. Reviewing what comes back
Read AI output the way you read a pull request from somebody you do not know. Here is a piece of generated code of exactly the kind you will be handed. Four things are wrong with it. Find them before you open the answer.
// "Renders the student list with a search filter"
function renderStudents(students, search) {
var html = '';
for (var i = 0; i < students.length; i++) {
if (students[i].name.includes(search)) {
html += '<li onclick="selectStudent(' + students[i].id + ')">'
+ students[i].name + ' - ' + students[i].score + '</li>';
}
}
document.getElementById('list').innerHTML = html;
var avg = students.reduce((a, b) => a + b.score) / students.length;
document.getElementById('avg').innerHTML = 'Average: ' + avg;
}Show me the four problems
1. The average is wrong in two ways. reduce with no starting value uses the first object as the accumulator, so it computes {...} + 88, producing a string like [object Object]88. And it averages all students rather than the filtered ones, which is almost certainly not what the label claims.
2. User text goes into innerHTML. A student named <img src=x onerror=...> executes. Day 4 and Day 17.
3. onclick written into a string. It depends on a global function, breaks under modules, and would be a delegated listener in anything written this month.
4. The search is case-sensitive, so typing "chidinma" finds nothing. And var in 2026 is a smell on its own.
None of those stop the page loading. Three of them produce output that looks fine until the wrong moment, which is exactly why "it ran" is not a review.
// proving problem 1, because it is the one people do not believe
const students = [{ name: 'Chidinma', score: 88 }, { name: 'Musa', score: 54 }];
console.log('no starting value:', students.reduce((a, b) => a + b.score));
console.log('with a starting value:', students.reduce((a, b) => a + b.score, 0) / students.length);4. Hallucinated APIs
The most dangerous output is not code that fails. It is code that looks completely reasonable and calls a method that does not exist.
const items = [3, 1, 2];
console.log(typeof items.sortBy); // sounds real, is not
console.log(typeof items.remove); // sounds real, is not
console.log(typeof items.toSorted); // real, and genuinely useful
console.log(typeof items.includes); // real
console.log(items.toSorted((a, b) => a - b), 'original untouched:', items);The ten-second check that saves an hour
When AI hands you a method you have not used before, search MDN for it by name before you build on it. If MDN does not have it, it either does not exist or is not something you should be relying on. This habit costs ten seconds and it is the single highest-return thing in this lesson.
5. The security failures AI hands you most often
| What it writes | Why it is wrong | Day |
|---|---|---|
el.innerHTML = userInput | XSS. The user can inject markup | 4, 17 |
| An API key inline in the JavaScript | Public the moment you deploy | 8, 17 |
eval() on anything | Runs arbitrary code. Almost never justified | 17 |
| Validation only in the browser | Trivially bypassed. The server must check | 13 |
Storing a token in localStorage | Readable by any injected script | 11, 17 |
These recur because the model learned from a decade of tutorials that did the same things. It is not being careless: it is reproducing the average of what people have published, and the average is not secure.
6. Use it as a reviewer, which is where it shines
The highest-value use of AI in this whole course is not generation. It is asking it to attack work you already did.
You are a senior JavaScript engineer reviewing a junior's code. Be strict and
specific. Do not compliment me.
Here is my code:
[paste it]
Answer:
1. Any bug that produces a wrong result rather than an error. Show me the input
that breaks it.
2. Anywhere user input reaches the DOM or a URL unsafely.
3. Anything that will break with 5,000 records instead of 50.
4. Three names that do not say what they hold.
5. The single change that would most improve this file, and why.
If you find nothing in a category, say so rather than inventing something.That last line matters more than it looks. Without it you get five findings whether or not there are five, because the shape of your question implied there should be.
7. The rule
Never submit code you cannot explain
Not "did not write". Cannot explain. Copying from Stack Overflow was always fine if you understood what you copied, and pasting from an AI is fine on exactly the same terms. If you cannot say what a line does and why it is there, it does not go in your project, because the moment it breaks you cannot fix it and the moment you are asked about it you cannot answer.
The three-question test, before any generated code goes in
- What does this line do? If you cannot say, ask for an explanation rather than pasting it.
- What happens with empty, zero, or 5,000 items? Try it. Do not reason about it.
- Could a user put something hostile through this? If user text reaches
innerHTMLor a URL, the answer is yes.
Do this now
- Take the broken code from section 3, fix all four problems, and write one sentence per fix explaining what would have gone wrong.
- Ask an AI to generate a small feature for your Day 15 project with your real data shape pasted in. Before you run it, write down what you think is wrong with it. Then run it and see if you were right.
- Run the reviewer prompt on a file you wrote yourself this month. Fix what it finds that is genuinely a problem, and write down anything it flagged that was actually fine. That second list is the point of the exercise.
- Find one hallucination. Ask for "five lesser-known array methods with examples" and check every one on MDN. Note which were real.
Checkpoint
Q1. What is AI genuinely good at, in one word?
Transformation. Explaining, rewriting, expanding, translating, generating practice material. It is weak wherever the task is judgement: what matters, what to build, whether this is right.
Q2. Why include "list three edge cases you did NOT handle" in a prompt?
It forces the model to argue against its own output, which surfaces the assumptions it quietly made. It is the cheapest quality improvement you can make to any code prompt.
Q3. You are given `array.sortBy()`. What do you do?
Search MDN for it before building on it. It does not exist. Ten seconds now against an hour of debugging a method that was never real.
Q4. What does "never submit code you cannot explain" actually forbid?
Not using AI, and not copying. It forbids shipping lines you could not defend if asked, whoever or whatever produced them.
Tick before you move on
- ☐ I found all four problems in the generated code before opening the answer
- ☐ I proved the reduce bug myself rather than taking it on trust
- ☐ I ran the reviewer prompt and noted where it was wrong as well as right
- ☐ I caught at least one hallucinated method against MDN
- ☐ Every line in my Day 15 project is one I can explain
Quick recap
AI is strong at transformation and weak at judgement · Paste your real data shape and your constraints, or you get plausible fiction · Review generated code as a hostile reviewer: innerHTML, keys, eval, reduce · Check unfamiliar methods on MDN before building on them · Never submit code you cannot explain
Tomorrow, Day 17: the security mistakes a junior developer is actually expected not to make.