Courses Learn Blog Contact
Get Started →
Lesson 19

Day 19: Career and Professional Readiness

A GitHub profile that reads as a developer's, CV lines with checkable numbers, and worked answers to the nine questions junior interviews actually ask, including the one about AI.

Webbo3 Level 2: JavaScript Development 11 min read Free

Webbo3 Level 2 · JavaScript Development · Day 19 of 20

Career and Professional Readiness

Turning four projects into something a stranger can assess in ninety seconds, and answering the questions you will actually be asked.

By the end of today you can

  • Present a GitHub profile that reads as a developer's rather than a student's
  • Describe a project on a CV in the language an employer recognises
  • Write about your work without either boasting or apologising
  • Answer the JavaScript questions that come up in nearly every junior interview
  • Answer the AI question honestly and well, because you will be asked

You have four projects. Somebody deciding whether to interview you will spend about ninety seconds deciding, most of it on your GitHub profile and one README.

Today is about making those ninety seconds work. It is a different skill from building, and it is worth learning on purpose.

1. Your GitHub Profile

Definition

Your GitHub profile is the page at github.com/your-username. For a junior developer it is the portfolio: the first place an employer looks for evidence that you can build.

Real-Life Example

A shop window. A passer-by decides in seconds whether to go in, from the four things on display, not from the storeroom behind them.

Types: What to Fix

  • Pin your four best repositories. Not your practice files. Twenty repositories named test, test2 and js-practice tell a visitor nothing.
  • A description and a live link on every pinned repository. One plain line in the description field at the top.
  • A README with a screenshot on every pinned repository, in the shape from Day 18.
  • Archive the noise. An empty repository from week one is not evidence of anything.
  • A profile README. Create a repository named exactly your username; its README appears on your profile. Three lines: what you build, what you are learning, how to reach you.
What this code doesWe want a profile README that says who you are, shows two pieces of real work with links, and tells people how to reach you, in under ten lines.
README.md
1
2
3
4
5
6
7
8
9
10
11
12
# Chidinma Okafor

Frontend developer in Lagos. I build things with vanilla JavaScript and I am
learning React.

**Recent work**
- [Job Tracker](https://chidinma.github.io/job-tracker): flags applications that
  have gone quiet. Vanilla JS, localStorage, Lighthouse accessibility 100.
- [Resource Finder](https://github.com/pod-3/resource-finder): team of five;
  I built the API layer and the search.

Reach me: [email protected]
NOTE   
Put this in a repository named exactly your GitHub username, and it shows at the top of your profile.

The Commit History Is Read, Though Not How You Think

Nobody counts green squares. They look for commits spread across days, because that shows sustained work, and for messages that say something. git log --oneline shows each commit on one line, the way a reviewer skims it.

What this code doesWe want to see a commit history the way a reviewer skims it, where every message says what changed, in the order it was built.
terminal
1
2
3
4
5
6
7
8
9
10
11
12
git init -q tracker && cd tracker
# A small helper: add a line to notes.txt and commit it with that message
commit() { echo "$1" >> notes.txt; git add notes.txt; git commit -qm "$1"; }

commit "Add application form and list"
commit "Save applications to localStorage"
commit "Flag applications with no reply after 14 days"
commit "Fix stale badge on exactly 14 days"
commit "Add keyboard focus to the status filter"

# Oldest first, one commit per line
git log --oneline --reverse
OUTPUT   TERMINAL
7674d2c Add application form and list
75b38df Save applications to localStorage
3fe8693 Flag applications with no reply after 14 days
50f97d3 Fix stale badge on exactly 14 days
4d226f8 Add keyboard focus to the status filter

Five lines, and a stranger can see how the project was built and that you fix your own bugs. Twelve commits called "update" on one afternoon tell a story too, and not a good one.

Picture This

Picture the shop window: four good things, clearly labelled, and the storeroom door shut.

2. Describing a Project

Definition

A CV line for a project says what you built, how you built it, and what it achieved. The difference between a line that gets skipped and one that gets read is entirely specificity.

Real-Life Example

"Good cook" on a chef's application is skipped. "Ran the grill station for a 120-seat restaurant, cut ticket times from 18 to 11 minutes" gets an interview.

WeakStrong
Built a to-do app with JavaScriptBuilt a task manager in vanilla JavaScript with create, edit, delete, filtering and search, persisting to localStorage and rendering from a single source of truth
Used an APIIntegrated a REST API with fetch, handling loading, error and empty states, and debounced search to cut requests from one per keystroke to one per pause
Worked in a teamWorked in a team of five with a branch-and-pull-request workflow; owned the API layer and reviewed twelve pull requests
Made it accessibleRebuilt the interface for keyboard-only use with managed focus and live regions, taking Lighthouse accessibility from 68 to 100

Each strong version names what, how, and what changed. The numbers matter: "68 to 100" is checkable, and checkable claims are the ones people believe.

Do Not Inflate. It Fails in the Room.

"Built a full-stack application" for a localStorage project falls apart at the first question, and everything else you said becomes suspect. Describing a frontend project precisely is more impressive than describing a backend project you did not build.

Picture This

Picture the chef's two applications side by side. Only one of them has a number you could phone the restaurant and check.

3. Writing About Your Work

Definition

A write-up is a short post about one real thing you built or fixed. For a junior developer it does more than another certificate, because it is evidence you can explain things, which is most of the job.

Real-Life Example

A mechanic who can tell you what was wrong with your car and why is trusted more than one who just hands back the keys, even if both fixed it.

What this code doesWe want an example of a post worth writing: one specific bug, the wrong first guess, the real cause, and the lesson.
post.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
The bug that taught me how JavaScript actually schedules work

My search box was showing results for the wrong query. Typing "lagos" gave
results for "lago". I assumed my filter was broken and spent an hour there.

It was not the filter. Every keystroke fired a request, they came back out of
order, and the last one to arrive won, which was often not the last one sent.

Two fixes. Debouncing, so one search runs per pause instead of one per letter.
And ignoring any response that is not for the current query.

What I actually learned: "it works when I test it slowly" is not the same as
"it works". I had only ever typed one letter at a time.

A post like that is stronger when the bug is shown, not just described. Here is the race it talks about. wait(ms) returns a promise that settles after that many milliseconds (Day 7), standing in for a slow network. The search for "lago" is made slower on purpose, the way a real server sometimes is.

What this code doesWe want to reproduce the bug from the post: two searches fired close together, answers arriving in the wrong order, and the older one winning.
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Stand-in for the network: settle after ms milliseconds
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// A fake search server: the "lago" request happens to be slow
async function search(query) {
  let delay = 50;
  if (query === 'lago') delay = 300;
  await wait(delay);
  return `results for "${query}"`;
}

// Whatever answer arrives last is shown
let shown = '';
async function onType(query) {
  const results = await search(query);
  shown = results;
  console.log('arrived:', results);
}

// The user types "lago" then "lagos" quickly
onType('lago');
onType('lagos');

setTimeout(() => console.log('on screen:', shown), 400);
OUTPUT   TERMINAL
➜ webbo3 node app.js
arrived: results for "lagos"
arrived: results for "lago"
on screen: results for "lago"

The fix from the post: remember the latest query, and throw away any answer that is not for it.

What this code doesWe want the same two searches, with a check that ignores any answer for a query the user has already typed past.
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function search(query) {
  let delay = 50;
  if (query === 'lago') delay = 300;
  await wait(delay);
  return `results for "${query}"`;
}

let shown = '';
let latestQuery = '';

async function onType(query) {
  latestQuery = query;
  const results = await search(query);

  // Stale: the user has typed something newer since this was sent
  if (query !== latestQuery) {
    console.log('ignored stale answer:', results);
    return;
  }
  shown = results;
  console.log('arrived:', results);
}

onType('lago');
onType('lagos');

setTimeout(() => console.log('on screen:', shown), 400);
OUTPUT   TERMINAL
➜ webbo3 node app.js
arrived: results for "lagos"
ignored stale answer: results for "lago"
on screen: results for "lagos"
  • A specific problem, not "10 JavaScript tips".
  • What you first assumed, and why you were wrong. This is the part people remember.
  • What you would do differently. It reads as judgement rather than as a tutorial.
Picture This

Picture the mechanic who explains: the same repair, and a customer who comes back.

4. The Questions You Will Be Asked

Definition

A junior technical interview checks that you understand the tools you used, not that you have memorised definitions. The strongest answer is short, correct, and ends with how you use it. Stronger still is one you have seen with your own eyes, so each answer below comes with its proof.

Real-Life Example

A driving test examiner does not ask you to recite the highway code. They ask why you checked the mirror, and they believe you because they watched you do it.

What is the difference between let and const?

Both are block-scoped. const cannot be re-assigned, but it does not freeze the value: an object in a const can still have its properties changed. I default to const and switch to let only where I genuinely re-assign, because it tells the reader the name will not move.

What this code doesWe want to prove that const stops re-assignment but not changes inside the object.
app.js
1
2
3
4
5
6
7
8
const student = { name: 'Musa', score: 54 };

// Changing a property inside the object is allowed
student.score = 61;
console.log('after changing a property:', student);

// Pointing the name at a different value is not
student = { name: 'Zainab' };
OUTPUT   TERMINAL
➜ webbo3 node app.js
after changing a property: { name: 'Musa', score: 61 }
TypeError: Assignment to constant variable.
What is the DOM?

A live tree of objects the browser builds from the HTML and draws the page from. JavaScript changes the tree, not the file, which is why a refresh undoes everything: the tree is rebuilt from the file again.

What is a Promise?

An object standing for a value that has not arrived yet. It is pending, then either fulfilled with a value or rejected with a reason, and it never goes back. async and await are syntax over the same thing, which is why an async function always returns a Promise.

What this code doesWe want to see a real Promise pending, then fulfilled, by logging the same promise twice.
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// An async function always hands back a Promise
async function loadName() {
  await wait(50);
  return 'Chidinma';
}

const promise = loadName();
console.log('straight away:', promise);

// Later, once it has settled
setTimeout(() => console.log('100ms later: ', promise), 100);
OUTPUT   TERMINAL
➜ webbo3 node app.js
straight away: Promise { <pending> }
100ms later:  Promise { 'Chidinma' }
What happens when you call fetch()?

It returns a Promise that resolves to a Response as soon as the headers arrive. The body has not been read yet, which is why response.json() is a second await. And it only rejects when the request could not be made at all: a 404 or a 500 resolves normally, so I check response.ok and throw myself.

What this code doesWe want to prove that fetch resolves, not rejects, when the server answers 404, so the catch block never runs.
index.html
1
<p id="out"></p>
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
async function load() {
  try {
    const response = await fetch('https://api.webbo3.test/courses/99');
    // No error was thrown: we get here even for a 404
    console.log('resolved, status', response.status, 'ok is', response.ok);
    document.querySelector('#out').textContent = `Resolved with status ${response.status}`;
  } catch (error) {
    console.log('rejected:', error.message);
    document.querySelector('#out').textContent = 'Rejected';
  }
}

load();
BROWSERindex.html · after a 404
CONSOLE   BROWSER DEVTOOLS
Failed to load resource: the server responded with a status of 404 (Not Found)
resolved, status 404 ok is false
What is the difference between map and forEach?

map returns a new array of the same length, one output per input. forEach returns undefined and exists for side effects. If I want a new list I use map; if I am just doing something with each item I use forEach.

What this code doesWe want to see what each one hands back when given the same work.
app.js
1
2
3
4
5
6
7
8
9
10
const scores = [54, 88, 71];

// map: builds and returns a new array
const fromMap = scores.map((score) => score + 5);

// forEach: runs for each item and returns nothing
const fromForEach = scores.forEach((score) => score + 5);

console.log('map returned:    ', fromMap);
console.log('forEach returned:', fromForEach);
OUTPUT   TERMINAL
➜ webbo3 node app.js
map returned:     [ 59, 93, 76 ]
forEach returned: undefined
How would you debug a broken API request?

Network tab first, because the Console cannot tell me whether the request even went out. Did it fire, what status came back, and what is actually in the Response tab. That tells a wrong URL from an auth problem from a shape I assumed. CORS shows as a failed request with a specific console message and is not fixable from the frontend.

What is event delegation and why use it?

One listener on a parent, using event.target.closest() to find which child was involved. Rows added after the listener was attached still work, whereas a listener per button only covers the buttons that existed at the time.

What this code doesWe want to prove delegation covers a row added after the listener was set up: we add a row, then click its button.
index.html
1
2
3
4
<ul id="list">
  <li>Ade <button class="remove">Remove</button></li>
</ul>
<button id="add">Add Bola</button>
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const list = document.querySelector('#list');

// One listener on the parent, set up before Bola's row exists
list.addEventListener('click', (event) => {
  const button = event.target.closest('.remove');
  if (!button) return;
  console.log('removing', button.closest('li').firstChild.textContent.trim());
  button.closest('li').remove();
});

// Added later: no listener of its own
document.querySelector('#add').addEventListener('click', () => {
  list.insertAdjacentHTML('beforeend', '<li>Bola <button class="remove">Remove</button></li>');
});
BROWSERindex.html · after adding Bola and removing him
CONSOLE   BROWSER DEVTOOLS
removing Bola
How do you stop XSS?

Put user text in with textContent, never innerHTML. If the feature genuinely needs user HTML, use a maintained sanitiser rather than my own regular expression. And browser validation is only a courtesy: the server has to check too.

The One Everybody Now Asks

How do you use AI when you code?

Answer honestly and specifically. "I don't" is not believed. "For everything" ends the interview. Something like: I use it to explain errors, for boilerplate, and as a reviewer: I paste my own code and ask it to attack it. I do not use it to decide what to build. I check any method I have not seen against MDN, because it invents plausible ones. And I do not commit anything I could not explain in a review, the same standard I apply to code I copied from anywhere else. That works because it shows a process, and every part of it is something you did this month.

The Preparation That Actually Works

Open each of your four projects and read the code aloud, saying what each block does. Every hesitation is a question you cannot answer yet. Twenty minutes per project is worth more than any list of questions, including this one.

Picture This

Picture the driving examiner: they believe the answer because they watched you check the mirror. Run the proof once and the answer is yours.

5. Where the Work Is

RouteWhat to expect
Junior frontend rolesRarely require a degree; do require evidence. Your four projects are the evidence
Agency and studio workA different project every few weeks. Fast, and you learn quickly
FreelanceSmall first. One finished job with a good review beats a certificate
Your own networkSomebody you know has a site with problems. Fix it, send a clean write-up, ask for a referral

Do This Now

  1. Clean your GitHub: pin four, describe them, archive the rest, add a profile README.
  2. Write four CV lines for your four projects, in the strong style above.
  3. Write one post about a real bug you hit this month, with the code that shows it.
  4. Record yourself for two minutes demoing your best project, then watch it back. It is uncomfortable, and it will change how you present on Day 20.
  5. Answer all nine questions above out loud, without reading the answers first. Then run each proof and check yourself.

Tick Before You Move On

  • ☐ Four repositories pinned, each with a description, README and live link
  • ☐ A profile README exists
  • ☐ Four CV lines written that name what, how and what it achieved
  • ☐ One written post published somewhere
  • ☐ I answered all nine interview questions out loud from memory

Quick Recap

Ninety seconds: profile, one README, one screenshot. Name what you built, how, and what changed, with checkable numbers. Do not inflate; a precise frontend project beats an invented full-stack one. Read your own code aloud: every hesitation marks a question you cannot answer yet. On AI, describe your process, because a process is what they are testing for.

Final Scenario

An interviewer asks what fetch does with a 404. You say it resolves, that you check response.ok, and that you know because you watched the catch block not run.

Then they ask about AI, and you describe the reviewer prompt, the MDN check and the rule you follow, each with an example from a project they can open while you talk.

You are not the most experienced person they will see this week. You may be the one who can show their working.

Tomorrow, Day 20: a client brief, a team, and everything you have learned in one build.

Learn this with a real instructor

Free lessons take you a long way on your own. The full programmes add live classes, assignments, Skill Points and a certificate — built for African students.