Java · SQL · Full-stack development

Kheagen Haskins

Kheagen Haskins holding a bulldog puppy

Full-stack developer working in Java and SQL, with most of my work on the backend. I am the only developer at a managed IT services provider, where I designed and built the reporting engine that produces every client's monthly report. Teaching is how I got here. A psychology degree led me into it, and teaching Java led me into building software full time.

Languages
Primary
Java, SQL Server
Working knowledge
HTML, CSS, JavaScript, Python, Rust

Experience

  1. Managed IT services provider

    Full-stack developer · to present

    I designed and built the company's reporting engine. It runs in production, and its monthly report covers every device the company manages, from laptops and servers to printers and switches. I also run it in production. A runbook I wrote covers the production deployment, and my deployment script checks the new version's health and rolls it back when the check fails.

    Design decisions
    25
    Each one is recorded in an architecture decision record, and each one is mine. Three of them are still proposals.
    Maven modules
    13
    • Libraries 8
    • Apps 5
    The libraries hold the sync, database and reporting code. Two of them, for AI and for writing back to the service desk, are still early. The apps are what people run: a web server, a desktop app and command-line tools.
    Automated tests
    2,800
    Across the engine's Java modules, with nearly 200 more in its Rust tools. Eight modules fail the build when their test coverage drops below a set minimum.

    One half of the engine syncs data from nine vendor systems into one database. The other half reads that data back out and turns it into configurable reports.

    1. 9 data sources Ticketing, monitoring, security, backups, training

      I built the API layers that read the company's ticketing, monitoring, security, backup and training systems over REST, GraphQL and JSON-RPC, and from a data warehouse.

    2. 1 database SQL Server, synced on a schedule

      I designed the schema and administer the SQL Server database.

    3. Domain model Tickets, hardware, backups, patches, security

      I designed the layer the reports read through. Each area of the business has its own interface, which returns typed records and keeps its SQL out of sight. The reports can only read the database; the sync is the only part that writes to it.

    4. Client reports A monthly PDF summary and an Excel hardware workbook, per client

      I design the PDF and Excel reports, laying the PDFs out in HTML and CSS. I also built the web page that configures each report.

    How I review my code

    As the company's only developer, I have always been the one Java engineer on the job. In place of peer review, I run layered AI audits, each covering one concern: correctness, conventions, documentation or test coverage. I repeat them until the findings turn trivial. They catch real mistakes, but a senior engineer sees what they miss, which is why working with experienced developers is a large part of what I want next.

    Service desk administration

    Alongside the engine, I am the system administrator for the company's service desk system. I configure its ticket types and workflows, and take on the occasional ticket that needs a developer.

Other roles

  1. TurtleJar

    Java tutor · to present
    Java and Python tutoring for high school and first-year university students.

    Alongside my development work I tutor Java, both to Grade 10 to 12 students on the IEB syllabus and to university students taking it in their first years. I also teach Python to first years. Most of the work is diagnosis. I find the idea a student has actually misunderstood, then explain it in terms they already understand.

  2. Independent school, Johannesburg

    Coding, robotics and IT teacher · to
    Taught IEB Information Technology in Java, and wrote the textbook for the course.

    From 2021 I taught IEB Information Technology to Grades 10 to 12, a syllabus taught in Java. I wrote a textbook for the course and coached matric students through their final-year projects, which meant explaining design, debugging and program structure to people meeting them for the first time.

    I joined as a coding and robotics teacher for primary school children, using LEGO Mindstorms EV3 robots and Swift Playgrounds. When Covid moved lessons online, I taught myself web development and taught HTML and CSS to Grade 4s.

  3. Royal Sitting Services

    Co-founder · to
    Co-founded a pet-sitting business that grew past what two people could run.

    My partner and I started a pet-sitting business while I was at college. Bookings filled up faster than the two of us could take them, so we interviewed and hired more sitters to keep up. Covid ended the business in 2020, just as I began teaching.

  4. Retail promotions agency

    Junior sales representative · to
    Sold GPS devices in Makro, approaching every shopper cold.

    I sold TomTom GPS devices to shoppers in Makro, a large retail chain, approaching each person cold. The job built my confidence in talking to strangers and persuading them.

Hard problems

These are the hardest problems I have solved in the reporting engine. I worked out how each of them should work myself. My starting point was the old reports, and sometimes the API behind their data.

  1. Syncing from a data warehouse billed per query

    The hardest source to sync was a data warehouse billed per query. Loading its tables into an empty database was quick to build. Keeping them up to date afterwards was the real work, and each fix exposed the next problem.

    1. Schema changes The vendor changed it without notice

      The vendor changed its schema without notice. Before the sync fetches anything, it now checks that it can map every column it will write, and it reports a mismatch as a schema failure.

    2. Slow or hung A slow response looked like a dead one

      Syncs began to hang, and nothing could tell a slow response from a dead one. I moved to reading 50,000 rows a page, with a time limit on each page, and a stalled page is retried on a fresh connection. Paging then raised the questions every sync has to answer, such as what to roll back when the sixth page fails, and what to do with half a page.

    3. Measuring A few tables took far longer

      I built diagnostic tables into the database that record each sync's errors and the time taken for every source and table. A day or two of production data showed a few tables taking far longer than the rest. I therefore moved those tables onto a schedule of their own, reading them four times a month to save warehouse credit.

    4. Finding changed rows Reading whole tables cost too much

      Reading every table whole on every run cost too much on the largest ones. Where a table has change-tracking columns, the sync now pulls only the rows that changed since its last run, in pages sorted on the table's key. A table without them is read whole, and the largest of those are read at most once a day.

    5. History A late request for every record's past

      To meet a late request for the history of every record, I added slowly changing dimension (SCD) tracking to the warehouse's three main tables and to seven tables from a second source. It keeps each past version of a record alongside the current one. When I measured the warehouse's history, 588,000 stored versions held only 50,000 distinct states, so a new version is kept only when a record actually changes. Each table has its own tracking policy for now, and I am working towards a general set of rules that new tables can follow.

    • Data warehousing
    • Paging
    • Incremental sync
    • Slowly changing dimensions
  2. Replacing hundreds of API calls with one query

    A vendor's REST API returned records one client and one page at a time, meaning collecting all of them took hundreds of requests in a row. I found a way to fetch the same data with a single query, and moved the collection onto it. Adding a new kind of data no longer means new API code. It takes a query file, a mapping from its columns to a Java record, and the table the rows land in.

    Collection speed
    186×
    The single query against the paged REST calls, as measured and recorded in the decision record that made the switch.
    • SQL
    • REST
    • Performance
  3. Separating the reports from the schema

    My first classes copied their tables. As a result, a changed table meant a redesigned class. Every piece of code that used the class then changed with it. I split the data layer into thirteen areas. Eleven match a part of the report, such as tickets, hardware, backups, patches, email security and security training. The other two hold the client list and each report's saved settings. Each area is an interface that returns typed records, and its SQL and implementation stay hidden behind it. A change to the database is now made behind those interfaces, where the reports never see it.

    • Domain modelling
    • Data access layer
  4. Branded charts in PDF reports

    The reports needed charts in the company's branding. The engine draws each chart as SVG from a client's data, with no chart library: eight chart types, from bar and line charts to gauges, each written in Java. The cover page, stat cards and score boxes are SVG files with slots the engine fills, so marketing can change their layout by editing a file. A report that still contains an unfilled slot fails rather than reaching a client.

    • SVG
    • Templating

Skills

  • Java

    • Java 25
    • Framework-free
    • JPMS modules
    • Records and sealed types
    • Virtual threads
    • JUnit 5
    • Mockito

    Hover to read how I use itTap to read how I use it

    Java

    The engine is a set of libraries that its apps call, rather than a framework that calls them. It is built on the standard Java APIs and a few small, focused libraries, and I wire it together by hand with plain constructor calls. A stack trace therefore follows my own code from the call to the failure.

    The sync's classes receive their dependencies through their constructors, meaning tests can pass in their own doubles. The sync runs its sources in the order their data depends on each other, and runs independent sources at the same time on virtual threads. The library modules seal their internals under JPMS, the Java module system. As a result, one module reaches another only through what that module exports.

  • Data

    • SQL Server
    • Data warehousing
    • HikariCP

    Hover to read how I use itTap to read how I use it

    Data

    I wrote the code that generates the sync's SQL from the schema and protects it from SQL injection. Where a source reports what changed, the sync loads only new and changed rows. A stalled query is retried on a fresh connection, and a table that fails catches up on the next run.

  • APIs

    • REST
    • GraphQL
    • JSON-RPC
    • OAuth 2.0

    Hover to read how I use itTap to read how I use it

    APIs

    Most vendor connections are rate-limited and retry failed calls with growing delays, waiting without holding a thread. Login tokens refresh safely while many calls run at once. Guards on the connections reject any call that could change data, since one vendor's token could reboot client machines.

  • Reports and apps

    • OpenHTMLToPDF
    • Apache POI
    • JavaFX
    • Undertow
    • jpackage

    Hover to read how I use itTap to read how I use it

    Reports and apps

    The engine produces Excel workbooks and PDF reports with charts. Every report keeps the same two rules: no section is ever left out, and no figure is shown for a period its data does not reach. Its apps ship as standalone programs that bundle their own Java runtime.

  • Tooling

    • Rust
    • Python
    • Maven
    • JaCoCo
    • Checkstyle
    • PMD
    • Spotless
    • Docker
    • Git
    • GitHub Actions

    Hover to read how I use itTap to read how I use it

    Tooling

    I write command-line tools in Rust for the jobs around a build that are slow by hand or easy to get wrong. The reporting engine uses several of them. They build and seed its test database, update the version tags in its Javadoc, and turn its SVG icons into app icons. Another counts lines of code, leaving out comments and blank lines.

    Every Maven module takes its dependency versions from one shared bill of materials (BOM). Eight modules fail the build when their test coverage drops below a set minimum, and Checkstyle, PMD and Spotless check the code's style. Tests also enforce the architecture: SQL has to live in its own files, and the library modules cannot pull in a logging backend. SQL Server runs in Docker for development and testing, and GitHub Actions builds and deploys the apps.

Projects

Recent

These show how I build software now, with development experience behind me.

  • GUI Exams

    2026 · GitHub

    Java mock exams for IEB Information Technology, where the learner's printed answers drive an animation.

    • Java
    • Swing
    • Records
    • Teaching
    Read more

    GUI Exams are Java mock exams for the IEB Information Technology syllabus. The first two papers are for Grade 10 and Grade 12. In a standard paper, the learner's program prints its answers as text. Here a window reads that text line by line and animates it. In the Farm Drones paper, each line the program prints sends a drone across a farm to water a field, and a wrong battery calculation shows up as a drone falling out of the sky.

    The window marks each part green, amber or red, and explains anything that is wrong.

  • Slicket

    2026 · GitHub

    A ticketing system in Rust, designed around an entity component system, with every AI contribution in its own commit.

    • Rust
    • Entity component system
    • Cargo workspace
    Read more

    Slicket is a ticketing system I am building in Rust. I administer a well-known service desk system at work and find it complicated to use. Slicket is my attempt at one that feels better. Its backend is designed around an entity component system (ECS), a design where each thing, such as a ticket, is a bare ID with its data stored in separate components. Systems then run the logic over every ID that has the components they need. It is at an early stage of design: the entity and component types are built, and the storage and systems come next.

    It also shows how I work with AI. On its dev branch, my work and the AI's go in separate commits, and each commit's author records whose work it contains. Anyone can see exactly where I used AI.

Earlier

I built these before I had any development experience, while I was teaching and then studying Java full time.

  • WordCheat

    2025 · GitHub

    Lists every playable Words With Friends move, highest score first.

    • JavaFX
    • Move search
    • JUnit 5
    Read more

    WordCheat is a desktop helper for the Words With Friends word game. The player drags the board and their letters into it, and it lists every move they can play, highest score first. It checks each placement against a list of about 168,000 English words. The check covers every crossing word the move forms as well, and each valid move is scored with the game's letter values and bonus squares.

    I built it because my mother always beats me at the game.

  • HackMaster

    2024 · GitHub

    The terminal hacking puzzle from Fallout 3 and 4, rebuilt as a desktop game.

    • JavaFX
    • MVC
    • Observer pattern
    Read more

    HackMaster recreates the terminal hacking puzzle from the Fallout 3 and 4 video games. The player picks a password from a screen of words, and each wrong guess reports how many letters are in the right place.

    Its screens update themselves whenever the game state changes, and it comes with a Windows installer.

Education

  1. 2020 to present

    Self-taught programming

    Certificates

    I learnt to program through my teaching, my development work and my own projects. I also relearnt maths on Brilliant, to use it as a tool. Each project led into the next.

    1. Noise generator Draws natural-looking textures and terrain from maths
    2. Maths The maths behind the noise
    3. ECS architecture The way data is laid out drives the design
  2. to

    Professional Java

    Full-time independent study

    After leaving teaching, I spent most of a year learning Java as industry uses it rather than as a school syllabus teaches it. I learnt Git, and worked through Codecademy's courses on Java and on the Spring framework.

  3. to

    Bachelor of Arts

    I completed a three-year BA at Varsity College Sandton (now Emeris), majoring in Psychology and Communication Science.

  4. 2014

    Matric

    I earned my National Senior Certificate at Maragon Private Schools (now Crawford Ruimsig).

Extras

Coding philosophy

How I choose tools, why my systems keep frameworks at arm's length, and how I work with AI.

Hobbies

Outside work I write code for myself, play chess, study mathematics and read computer science.