Skip to content

Jafar Al-Fatlawi

Software Engineer @ Swibit

The spark

I'm Jafar. I was always going to take something apart. It just took a while before anyone paid me for it.

I have no memory of this, which is probably for the best. I have been told the cable came out, and that the investigation was concluded by an adult moving considerably faster than usual.

I was a curious child in the way that costs a household money. If a thing had an inside, I wanted to see it, so toys came apart and did not always go back together. I owned no screwdriver, so I turned screws with a fingernail. This works far more often than it should, and I have to report that I enjoyed it. Possibly too much.

The machine in that second photograph was not only for Paint. I was gaming on it at three, which by some accounting makes me one of the oldest gamers I know. Purple Place, mostly. I was not good at it.

I also had a bird, and the two of us used to listen to Yanni’s Playing by Heart together. I am not going to claim he had an opinion about it, but he stayed for the whole thing every time. The music came from a tiny MP3 player nobody had shown me how to use, which I worked out anyway by pressing everything until the pattern appeared.

That turned out to be the actual skill. Not the player, but the pressing. Give me long enough with almost any piece of software and I will find out how it thinks, and I have never really needed the manual to be there.

Everything after this is the same instinct with better tools. The curiosity never stopped.

Learning out loud

The Code People, 2024.

A bootcamp does not teach You to code. It teaches You to keep going after the fourth thing breaks at one in the morning.

The Code People was six months of building in public and breaking things loudly, surrounded by people doing exactly the same. That turns out to be the part that matters. You can learn syntax from a video. You cannot learn what to do when nothing works from a video, because the video never has Your bug.

I came sixth, and I knew why. There were things my colleagues were simply better at, and I had spent the final month running on empty and shipped a project I knew was not my best work. Both of those were true at the same time, and neither of them was the interesting part.

What that place gave me was somewhere safe to be visibly bad at something. You cannot fix what You will not let anyone see, and I had six months of people looking at my work and telling me the truth about it. The tutors were extraordinary at that: precise about what was wrong, and never once about who wrote it.

So the placing turned out to matter a great deal less than the habit. Find the gap, name it, close it, repeat. That is the whole method, and I have used it every week since.

These are the people I learned it with. Most of them I still talk to, and several I would call friends rather than former classmates. We were bad at this together first, which turns out to be an unusually strong foundation for a friendship.

The single best thing about that room was that You could always find someone who cared about the same problem You did, at the same hour of the night.

Going professional

Swibit, from December 2024.

On 24 December 2024 I started at Swibit, and my code stopped being mine.

That is the real difference, and nobody warns You about it. A personal project has one user, who already knows which button is broken. Production has people on a bus, on a poor connection, on an inexpensive phone, in a language that reads right to left, expecting something to work.

Most of what I have learned since came from problems with no answer in a library: things a dependency would not hand over, things that had to happen in the time between two camera frames, things that reported success while quietly failing. The specifics belong to the people who paid for them. The habits they produced are mine.

The other half of the job took longer to notice. Getting a feature working is the easy part. Leaving it in a state where the next person can change it safely is what decides whether a codebase is still worth working in two years later. That is where most of my attention goes now.

The next chapters are the technical ones. Same person, steadier voice. I cannot show You the code, so I have described the shape of the problems and what they cost.

Reading the chip

eMRTD · ASN.1 · cross-platform native patching

A national ID card carries a chip. Reading it means proving to the card that You are allowed to, using a key derived from the text printed on its face. So the flow is: photograph the card, read the printed zone, build the key, unlock the chip, take what is inside.

  1. capture card
  2. read the printed zone
  3. build the key
  4. authenticate(library)
  5. read the chip(library)
  6. decode
  7. validate

The library that handled the authenticated read returned a handful of fields. The ones the product actually needed were not among them: they sat in a part of the chip the library opened, checked was not empty, and then never exposed. From the application they were simply unreachable.

So I patched the library on both platforms to surface the raw bytes, in each platform’s own language, along with the type declarations so the new data existed as far as the application was concerned. The patch applies automatically on install, which is the difference between a fix and a note in someone’s working copy.

Then I wrote the decoder those bytes needed, from the specification up. Binary structures of this kind are not difficult so much as unforgiving: every length is declared in one of several ways, containers nest inside containers, and a single byte read at the wrong offset produces confident nonsense rather than an error.

On top of that sits the part that decides whether to believe any of it. Check digits, a normaliser for the places where two sources disagree about the same value in harmless ways, and a weighted score comparing what the chip said against what the camera read.

the parsing primitives
93 of 93 lines
the validation layer
88 of 88 lines
the orchestrating service
266 of 267 lines
the native patch
both platforms, plus type declarations
the feature document
397 lines, including its own limitations

Making it permanent

394 files, measured first

A product had grown the way products do. One component took thirty-six props. A single file had passed a thousand lines. The same few lines of authentication logic had been copied into seven of nine routes. None of it was broken. All of it was getting harder to change.

This is the work I care most about, and it is worth saying why. Writing a feature is a day. Living with it is years. Almost every codebase that becomes unpleasant to work in got there without a single bad decision: it got there through a hundred reasonable ones, each of which made the next change slightly more expensive. Nobody is ever assigned that problem, which is why it survives.

So I measured before touching anything. The plan opens with a dated table of every signal: prop counts, file lengths, duplication counts, patterns that were already legacy, and a note that there were zero circular dependencies with an instruction to keep it that way. Without a baseline, "I cleaned up the code" is unfalsifiable, and unfalsifiable claims are how this work quietly gets skipped.

Measured before, measured after
measurebeforeafter
component props367
component lines267142
split-pane props224
largest file, lines1,00251
login screen lines14343
duplicated auth redirects70

It was phased, and explicitly not batched: each phase independently shippable, each one test-first. That discipline is what let me reorder the plan partway through, when the evidence said the order was wrong. Two phases were going to move code and then decompose it. Measuring said the reverse, so I swapped them and wrote down why. Moving complexity is not reducing it.

The prop bloat had a cause worth naming. Those thirty-six props were not thirty-six pieces of state. They were a handful of objects that already arrived whole, re-spelled field by field at every layer down. Passing the objects fixed most of it. Three of the props turned out to be dead.

A refactor that is not enforced decays, which is why the second half of this work matters more than the first. The rules became executable: eight checks that run before a commit lands, each one encoding a decision the team had already made and would otherwise slowly forget.

files changed
394
custom rules
8, pre-commit and in CI
the coverage checker
has its own 413-line test suite
test-to-source ratio
roughly 0.8, across 85 test files
versioned agent skills
27, locked like dependencies
alignment checker
514 lines, runs in CI

The same discipline went to the AI tooling: skill documents written for that codebase specifically, versioned and locked the way dependencies are, with a job in CI that fails when the instructions given to one tool drift from the instructions given to another.

The point is not that an agent writes some of the code. It is that the same architectural rules bind a person and an agent identically, and neither can quietly violate them. That is the part I would want to be judged on. Not the refactor, but whether it survives the next person, who will not know why any of it is the way it is.

What else I've built

Release engineering · computer vision · geometry · i18n

Four other areas the work covers. All of it has shipped; none of it is a course I once took. More detail here in time.

  • Release engineering

    A five-stage pipeline covering checks, tests, builds and store submission, across three environments and two platforms. The failure I am proudest of fixing reported success on builds that had quietly expired: solved by verifying the real state through the API instead of trusting a status field.

    488 lines · 27 jobs · 3 environments

  • Computer vision

    A document-capture pipeline built from scratch before a library replaced it. Finding the four corners of a card in a live camera frame, checking the shape against the real physical dimensions of the thing, correcting the perspective, and drawing the result back over the preview as it moves.

    ~6,400 lines · runs per frame on the UI thread

  • Computational geometry

    Grid and mesh work for a floor-plan editor. I built the clever version, the one that leans a grid to follow slanted edges, then found it produced crooked lines whenever a shape had been drawn carelessly. So I reverted it and wrote down why, along with what it would take to do properly.

    reverted the clever one, documented why

  • Internationalisation

    Arabic and English with full right-to-left support, backed by checks rather than by discipline: a gate that fails when a translation is missing, a rule banning hardcoded user-facing text, and another banning hardcoded colour so the theme stays the single source of truth.

    enforced in CI, not by review

The geometry one is the story I would rather be asked about. Shipping the robust version and writing down why the prettier one failed was harder than building either of them.

What I actually know

Grouped by evidence, not by confidence.

Grouped by how much of it I have actually done, rather than by how confident I feel. The note under each group is what the claim rests on.

Core

Daily, on a production codebase of roughly a hundred thousand lines.

  • TypeScript
  • React
  • React Native
  • Expo
  • Redux Toolkit
  • Tailwind / NativeWind

Systems and platform

Where the library stops and You have to go under it.

  • Supabase
  • Native modules (Kotlin, Swift)
  • Reanimated worklets
  • Skia
  • ASN.1 / TLV
  • ICAO 9303
  • OpenCV
  • Metro platform resolution

Engineering practice

The half of the job that decides whether the codebase is still pleasant in two years.

  • CI/CD (GitLab, EAS)
  • Vercel
  • Test-driven development
  • Custom static analysis
  • Large-scale refactoring
  • Technical writing

AI

Both halves: building with it, and building the guardrails that make what it writes safe to merge.

  • Agent orchestration
  • Tool-calling clients
  • Skills and rules as versioned source
  • Sandboxed execution
  • AI governance in CI

Currently learning

This site is the exercise, including the parts I got wrong first and had to do twice.

  • Next.js
  • App Router
  • React Server Components

Swimming

Where I go to find out how I am doing.

I swim. It is my main health metric: how the water feels tells me more about my cardiovascular, neurological and mental state than any number I could write down.

Lately that has turned into freediving. Forty metres on one breath, and three minutes holding it, which sounds more impressive than it is. Almost none of that is lung capacity. It is learning that the urge to breathe arrives long before anything is actually wrong, and then staying calm enough to let it pass.

Calm is the whole skill. Panic burns oxygen faster than swimming does, so the training is mostly about not doing anything. I have found that useful in more places than the pool.

I built myself a training tool for it, naturally. Built once, runs forever, needs no maintenance. That is the same thing I want from production code.

Piano

Five pieces, and one of them is in this website somewhere.

I play piano. Five pieces so far, which is not many, and each one took as long as it took.

The one I keep returning to is The Bear, Oslo version, by Avery Bright. It has been on repeat for most of the time I spent building this site, so some of it is probably in here somewhere.

The rest: My Last Memory by Shaun Taylor-McManus, Reverie by Victor Borge, Dreaming in Color by Philip Wesley, and Epilogue from the No Man’s Land soundtrack. I learned Dreaming in Color in three days, which I have never repeated and no longer expect to.

I have also had the time, fortunately, to write a few small pieces of my own. They live on SoundCloud. Nothing polished, and I am fine with that.

If You would rather know what I listen to than what I make, my Spotify is the more honest answer. A great deal of Thomas Bergersen, which probably explains more about the rest of this site than I would like it to.

On a good day it is three hours. On others, none. I stopped apologising for that some time ago.

Still writing it

The shelf, and what goes on it.

This is the part that is not finished, and is not supposed to be.

There is a great deal I do not know, and the list gets longer the more I learn, which I have decided to take as a good sign. What I want most is to keep going further down than a library boundary usually asks for, and to get better at pulling working ideas out of other people’s writing instead of only out of things I have personally broken. That second one is the expensive gap.

Notes will land below as I write them. Things I worked out, things I got wrong, and the occasional piece of a specification that took a week to understand and should have taken an afternoon.

No posts yet. The shelf is built; I have not put anything on it.

I type at about 90 words per minute, which matters less than it sounds. It is mostly why I care about editor ergonomics and keyboard-first interfaces more than is strictly reasonable.

Say hello

If You want to brainstorm something, ask about any of this, or just chat, write me a message below. I read everything that arrives.