AboutExpertiseProjectsJourneyBlogContact
Discuss
AboutExpertiseProjectsJourneyBlogContactDiscuss

Yao David Logan

Software Engineer fullstack specialized in SaaS, business automation and scalable web/mobile platforms.

NavigationExpertiseProjectsJourneyBlogContact
LinksGitHubLinkedInEmail
© 2026 Yao David Logan. All rights reserved.
Clean code and technical debt — nine months teaching fullstack
Back to blog

Retour d'experience

Xin@

Clean code and technical debt — nine months teaching fullstack

YDLYao David Logan9 min readMay 23, 2026

CategoryRetour d'experience

Read9 min read

PublishedMay 23, 2026

Views59

Shares0

Comments0

Contents
  1. 011. The context
  2. 022. What we say isn't what we do
  3. 033. The rule that changed everything: "your code will be read 10 times"
  4. 044. The anti-patterns I saw most
  5. 055. Git discipline
  6. 066. Systematic pair programming
  7. 077. Project-based evaluation
  8. 088. Technical debt seen by a beginner
  9. 099. Tools that mattered
  10. 1010. What changed in my own practice
  11. 1111. Pitfalls to avoid in training
  12. 1212. Closing

Precise naming, early returns, short functions, daily refactor, pair programming and project-based evaluation: what nine months training 18 learners taught me about my own code.

Nine months teaching fullstack development to career-switchers. What I learned about clean code, technical debt, and real pedagogy.

1. The context

From July 2024 to March 2025, I trained a cohort of 18 learners at IAFP La Pyramide (a state-accredited modular training institute in Togo). Program: algorithmic fundamentals, JavaScript, TypeScript, Dart, Next.js, Flutter, React Native, Git. Goal: that they ship autonomous fullstack applications by the end.

Final certification rate: 85%. But that's not what marked me most. What marked me is what I learned about myself on code and technical debt by watching beginners write it for the first time.

2. What we say isn't what we do

First shock: what I thought was "instinctive" in my code isn't. When I name a function fetchUserPortfolio, I know why I didn't write getData. But that knowledge is implicit. A learner writes getData and doesn't see the problem — because it works.

Clean code isn't an aesthetic ruleset. It's a communication contract between the code and the future reader (which will be you in 6 months). That contract isn't innate. It's learned by watching others' code break in production.

I had to verbalize things I'd never explained: why a 3-letter variable name in an 80-line function is a drama, why a 5-level nested if is debt, why a comment paraphrasing the code is noise.

3. The rule that changed everything: "your code will be read 10 times"

First thing I hammered: code is read 10 times more than it's written. Not by marketing — by math.

A project lives 2–5 years in production. During that time, you re-read it:

  • To add a feature
  • To fix a bug
  • To explain to a colleague
  • To port to a new tech
  • To report to the PO

If writing a function takes 10 minutes but making it readable takes 12, the initial overhead is recovered at the first debug.

I enforced this with a practical rule: every PR must be explainable aloud in 2 minutes. If the learner couldn't, the code was too dense, too confused, or did too much. Refactor before merge.

4. The anti-patterns I saw most

4.1 Vague names

data, info, result, temp, val. Symptoms of "I don't know what to call it but it works."

Fix: always name by what it is, not by what it is technically. Not array, but activeUsers. Not fn, but computeMonthlyRevenue.

TypeScript
1// ❌ Vague
2function getData(id: string) {
3 const res = await fetch(`/api/users/${id}`);
4 const data = await res.json();
5 return data;
6}
7 
8// ✅ Precise
9async function fetchUserProfile(userId: string): Promise<UserProfile> {
10 const response = await fetch(`/api/users/${userId}`);
11 return response.json();
12}

4.2 Functions that do everything

I saw 200-line functions that validated, fetched, transformed, persisted and notified. All in one.

Rule: one function = one verb = one responsibility. If the name contains an "and", it's suspect. If you have to scroll to see the end, it's broken.

Practical limit taught: 30 lines per function, mandatory refactor at 50. Not a dogma, a warning signal.

4.3 The pyramid if

TypeScript
1// ❌ Pyramid
2function processOrder(order) {
3 if (order) {
4 if (order.items.length > 0) {
5 if (order.payment) {
6 if (order.payment.status === "valid") {
7 // ... 40 lines of logic
8 }
9 }
10 }
11 }
12}
13 
14// ✅ Early returns
15function processOrder(order: Order): OrderResult {
16 if (!order) return { ok: false, reason: "no_order" };
17 if (order.items.length === 0) return { ok: false, reason: "empty_cart" };
18 if (!order.payment) return { ok: false, reason: "no_payment" };
19 if (order.payment.status !== "valid") return { ok: false, reason: "invalid_payment" };
20 
21 // main logic, flat
22}

The if pyramid is slow sugar that piles up. Early returns flatten the code. Always reject first, process after.

4.4 Paraphrasing comments

TypeScript
1// ❌ Noise
2// Increment the counter
3counter += 1;
4 
5// ❌ Liar: comment becomes wrong when code changes
6// Fetch active users of the last 30 days
7const users = await User.findAll({ where: { lastSeen: { [Op.gt]: thirtyDaysAgo } } });
8 
9// ✅ Comment the why, not the what
10// 5-min cache to reduce DB load — see incident 2025-01-14
11const users = await User.findAll({ ... });

Rule taught: comments explain what code cannot. Don't paraphrase. If code is confused to the point of needing a comment to understand, refactor first, comment second.

4.5 Nameless parameters

TypeScript
1// ❌ What's this true? And this 30?
2createUser("Alice", "alice@test.com", true, 30);
3 
4// ✅ Object with explicit fields
5createUser({
6 name: "Alice",
7 email: "alice@test.com",
8 isAdmin: true,
9 ageYears: 30,
10});

Practical rule: 3 parameters max, beyond that use an object. The call-site becomes self-documenting.

5. Git discipline

90% of learners arrived with an empty GitHub account or a single "Initial commit". Early imposed:

  • Branches per feature, never direct to main
  • Atomic commits (one commit = one coherent change)
  • Descriptive present-tense messages (add login form, not added login form)
  • PRs with description: "what does this change, why"
  • Peer review before merge

The goal wasn't git perfection. The goal was to anchor the culture of public code. Once they understood their code would be read, habits flipped.

6. Systematic pair programming

One hour per day of forced pair programming (driver/navigator). At start, painful. After 2 weeks, visible transformation:

  • Learners verbalize their reasoning
  • Errors caught in 30 seconds instead of 30 minutes
  • Technical vocabulary aligns across the cohort
  • The "asking isn't weakness" culture sets in

It's also where I saw the best developers emerge: not necessarily those who coded fastest, but those who asked the best questions.

7. Project-based evaluation

I removed theoretical QCMs. Instead: an end-of-module project, defended orally before the cohort.

Criteria:

  1. Code runs and does what it claims (50%)
  2. Code is readable by a dev who didn't write it (25%)
  3. Code handles foreseeable errors (15%)
  4. Code has a README and a deployment (10%)

No bonus for "pure performance" or "advanced techniques". Just deliverable and communication quality.

This grid killed rote learning and forced understanding. The best learners weren't those who memorized the most syntax, but those shipping the clearest code.

8. Technical debt seen by a beginner

Most surprising: beginners see technical debt better than we think. They just can't name it.

When a learner arrives saying "I don't understand my own code from yesterday", they wrote debt. When they say "it works but I don't know why", it's a signal to refactor before continuing.

I institutionalized the "daily refactor": every morning, 30 minutes, each learner re-reads yesterday's code and improves it. This practice alone changed the cohort's average level in 6 weeks.

9. Tools that mattered

  • ESLint + Prettier: automation of aesthetics to skip the debate
  • TypeScript strict: so logic errors become compile errors
  • VS Code + GitHub Copilot: only for boilerplate, NEVER for business logic (otherwise they don't learn)
  • Cypress / Playwright for E2E tests on final projects
  • Vercel / Railway for deployment (free, fast, motivating)

10. What changed in my own practice

Three things I changed in my code after this mission:

  1. I name better — verbalizing in front of learners forced me to see my bad names
  2. I refactor earlier — seeing debt pile up in accelerated form with beginners made me allergic to letting a file degrade
  3. I write fewer comments — I prefer an explicit name to a descriptive comment

11. Pitfalls to avoid in training

PitfallSymptomFix
Theory without practiceLearners reciting without understanding70% practice minimum
Frameworks without foundationsStuck when framework changesStart with pure JS, add later
Theoretical evaluationRote memorizationProject-based evaluation
No Git earlyDangerous solo habitsBranches from day 3
Copied tutorials without understandingStuck off the beaten pathForce solo debugging before help
No pair programmingLoneliness + accumulated debtDaily forced sessions

12. Closing

Teaching made me a better developer, more than any training I've taken. Verbalizing tacit choices, explaining why a name is bad, watching debt being created in real time — all of that changes how you write your own code.

If you get a chance to teach, take it. Not for the pay (often weak), not for the status (often ignored). For what it teaches you about your own craft.

Clean code isn't a code requirement. It's a future-reader requirement. And the future reader is you.

Comments

Reader reactions

No comment yet

No spam — email is only used to verify your identity.

·

Be the first to share your reaction.

←PreviousFrom MVP to traction — 8 patterns to avoid shipping a sleeping B2B SaaSBusiness · 8 min read
Next conversation

Turn this reading into a product decision.

If this topic feels close to a real product problem, I can help on diagnosis, architecture, backend, interface and automations that make a platform usable in production.

Format
Full-time, freelance, long mission
Focus
SaaS, API, back-office, automation
Discuss the topicDownload CV

Newsletter

Get the next technical notes.

A short selection on SaaS, backend architecture, business automation and product quality. No noise, only applicable ideas.