Career

Transitioning 6 SIWES Interns to Production Backend Engineers in 90 Days: A Neobot Case Study

O
Oluwaseun AlabiTechnical Director
October 1, 202611 min read
Transitioning 6 SIWES Interns to Production Backend Engineers in 90 Days: A Neobot Case Study

Most Nigerian CS graduates and bootcamp alumni arrive with theoretical knowledge or isolated tutorial projects, but lack experience with production edge cases. Here is how we built a 90-day apprenticeship system that turned six SIWES interns into reliable backend engineers shipping production code.

Every year, thousands of Nigerian university students enter the Students Industrial Work Experience Scheme (SIWES) or the National Youth Service Corps (NYSC) looking for software engineering placements. Most arrive with one of two backgrounds: academic Computer Science degrees heavy on relational algebra and Java syntax but devoid of modern cloud infrastructure, or coding bootcamp certificates built entirely on tutorial-driven React apps and simple Express CRUD APIs.

Neither background prepares an engineer for what happens when a database connection pool exhausts during a high-traffic payment surge, or how to write an idempotent background worker. At Neobot Tech, we do not have the luxury of letting junior engineers spend six months passively watching senior engineers share screens. We build mission-critical backend systems for startups across West Africa, and our senior engineers need high-leverage contributors, not perpetual observers.

In Q1 2024, we took on a cohort of six SIWES interns and NYSC associates. Instead of assigning them to non-critical internal tools or letting them flounder in tutorial hell, we structured a rigorous 90-day apprenticeship framework. Within three months, all six were writing tested, production-ready TypeScript and Go code running on live client infrastructure.

Here is how we set up the environment, what failed during our first iteration, and the exact blueprint you can copy for your engineering team.

A flowchart mapping out Neobot's 90-day engineering apprenticeship progression from synthetic debugging to production ownership

The Situation: The CS Degree and Bootcamp Reality vs. Production Backend Systems

When our cohort arrived, their theoretical foundational logic was intact, but their operational mechanics were absent. In university courses, exceptions are caught with empty catch blocks or printed to stdout. In bootcamps, state is kept in memory, and single-instance Node.js servers run without process managers or environment isolation.

During initial technical diagnostic sessions, we identified three major knowledge gaps:

  1. Concurrency and Data Integrity: None of the candidates understood database locks, race conditions, or why running multi-step financial operations inside an un-isolated HTTP route leads to double-spending.
  2. Observability and Failure Modes: Errors were treated as fatal bugs rather than expected system states. Writing structured logs, handling transient network timeouts, or inspecting tracing headers was unfamiliar territory.
  3. Asynchronous Communication: The candidates were accustomed to real-time verbal instructions. They had no experience writing formal Request for Comments (RFC) documents, system design specs, or descriptive Pull Request (PR) context.

We needed to bridge this gap fast without blowing up our engineering budget or draining senior engineering bandwidth.

Operational Constraints: Zero Error Margins on Financial Infrastructure

Most of our active client projects handle actual money, sensitive user identity data, or flaky telco APIs. We couldn't assign junior engineers to "toy" microservices that had no business context because isolated sandbox exercises don't build operational intuition. However, we also couldn't allow unvetted code to hit primary services.

Our constraints were firm:

  • Senior Engineering Time Cap: Senior engineers were allowed to spend a maximum of 4 hours per week per intern on direct 1-on-1 instruction. Mentorship had to scale asynchronously.
  • Zero Production Downtime: Every line of code written by an apprentice had to pass through automated static analysis, strict integration test suites, and explicit isolation barriers before reaching staging or production environments.
  • Real Economic Context: Interns had to work on production-adjacent tickets—such as adding webhook retries, optimizing slow SQL queries, or handling edge-case API responses—from week four onward.

When we structured our interviewing process for this cohort, we avoided LeetCode algorithmic trickery entirely. As detailed in our engineering evaluation guide on Evaluating Senior Engineers in Lagos: Why Live Coding Fails and 3-Hour Distributed Debugging Sessions Win, real engineering aptitude shows up when an engineer interacts with broken systems, reads logs, and reasons through failure modes under pressure.

What Failed: Tutorial Hell and Unsupervised Shadowing

Our initial attempt at running an internship program two years ago was a disaster. We tried two traditional approaches, both of which failed miserably:

Failure Mode 1: The Video Course Dump

We bought the interns top-rated Udemy and Pluralsight courses on Docker, Kubernetes, and Advanced Node.js, setting them loose for two weeks to "learn the stack." The result? High completion percentages, zero ability to debug a real-world circular dependency, and total paralysis when facing a 5000-line client repository.

Failure Mode 2: Unsupervised Shadowing

We paired interns directly with senior engineers on client calls and screen-sharing sessions. The senior engineers naturally took over the keyboard whenever a complex bug appeared because client deadlines were looming. The interns became passive spectators. They absorbed basic terminal syntax, but learned zero problem-solving stamina.

We realized that engineering capability is built through cognitive discomfort and immediate feedback loops, not passive absorption.

What Worked: Synthetic Production Breakage and Asynchronous RFC Culture

We completely redesigned the 90-day pathway into three distinct 30-day phases. We shifted from teaching languages to teaching system behaviors.

| Onboarding Phase | Core Technical Focus | Primary Deliverable | Senior Mentorship Commitment | | :--- | :--- | :--- | :--- | | Phase 1 (Days 1–30): Diagnostic Breakage | Debugging, log analysis, local environment parity, writing regression tests | Fixing 15 deliberately broken, simulated microservices | 4 hours/week (Async PR reviews & Debug guidance) | | Phase 2 (Days 31–60): The RFC & Isolated Feature Phase | System design specs, idempotency, advisory locks, queue processing | Writing 1 RFC and delivering 1 non-blocking service feature | 2.5 hours/week (RFC review & Architecture approval) | | Phase 3 (Days 61–90): Production On-Call & Refactoring | Observability, P99 latency tuning, webhook retry loops, database migrations | Shipping 5+ production PRs and co-piloting on-call rotations | 1 hour/week (Final PR sign-offs & Post-mortem reviews) |

1. The Broken Sandbox (Days 1–30)

Instead of giving candidates a fresh repo and asking them to build a REST API, we handed them a multi-container Docker application that was subtly, deliberately broken.

We introduced real-world bugs into the repository:

  • A Redis cache that never invalidated, causing stale user sessions.
  • A database call inside a loop causing an N+1 query performance bottleneck.
  • A webhook endpoint that failed when given a payload containing West African special characters or missing authorization headers.

Their job was not to add features. Their job was to inspect the logs, reproduce the failure using a written integration test, fix the bug, and open a PR. According to the Google Engineering Practices Documentation, strict code review standards act as the primary mechanism for knowledge transfer. We held their PRs to full production standards from day one—demanding explicit variable naming, comprehensive test coverage, and proper error propagation.

2. Mandatory Architectural RFCs Before Code (Days 31–60)

Before writing any non-trivial business logic, apprentices were required to author a light, one-page Request for Comments (RFC). If an apprentice was assigned to build an offline mutation queue for mobile clients, they had to detail how local state syncs with the remote Postgres instance when connections drop—similar to the patterns described in our article on Offline-First React Native: Building an Idempotent SQLite Mutation Queue for Flaky 2G Networks.

Here is the exact RFC template we mandated:


### 1. Problem Context
What specific failure mode or missing functional requirement does this address? 
Include relevant log snippets or Sentry issue IDs.

### 2. Proposed Architecture & Data Flow
- How does data flow from client -> API gateway -> service -> database?
- What database locks or isolation levels are required? (e.g., Postgres Advisory Locks vs. SELECT FOR UPDATE)

### 3. Failure Modes & Edge Cases
- What happens if the downstream telco/payment provider times out after 15 seconds?
- How is state recovered if the background worker pod dies mid-execution?

### 4. Verification Plan
Write out the specific integration test cases that will run in CI to prove this fix.

Writing this document forced candidates to think through concurrency edge cases, system boundaries, and network failures before touching their code editors.

3. Automated CI/CD Guardrails

To protect senior engineer sanity and ensure client infrastructure stayed rock-solid, we automated 80% of code hygiene enforcement using GitHub Actions. We configured strict linter rules, branch protection gates, and automated test coverage tools.

Here is a representative workflow block we added to our apprentice repos to reject any code that lacked proper error handling or dropped test coverage below threshold:

name: Apprentice Pipeline Security & Quality Gate

on:
  pull_request:
    branches: [ main, staging ]

jobs:
  quality-gate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js & Tooling
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'

      - name: Install Dependencies
        run: npm ci

      - name: Run Static Security & Linter Analysis
        run: npm run lint

      - name: Execute Integration Test Suite
        run: npm run test:coverage

      - name: Verify Code Coverage Floor
        run: |
          COVERAGE=$(npx nyc report --reporter=text-summary | grep 

Neobot Engineering Standard

Every system deployed by Neobot Tech incorporates enterprise baseline practices. We continuously audit our database topologies, REST API query paths, and frontend modular bundles to prevent latency spikes and ensure top-tier security posture.

Tags:#Full-size, production/staging test harness pattern#Next-Level Apprenticeships#Mocking strategies for flaky external APIs (Paystack, NIMC, Telcos)#Step-by-step mentor onboarding pipeline#Metrics-driven performance tracking

Discussion

Comments Coming Soon

We are currently migrating our discussion engine to a new real-time database schema. Check back shortly to join the conversation.