Skip to content
Tarik Hireche
Portrait of Tarik Hireche

Bilingual Software Developer

Tarik Hireche

I like working on the layer under the application, where the processes, containers and pipelines live. Most of what I know there I picked up by building something and then taking it apart.

  • Java
  • C#
  • SQL
  • Cloud & Infrastructure
Degree
B.Sc. Computer Science · Université de Montréal (DIRO)
Focus
JVM services, containers, CI
Degree
B.Sc. Computer Science, UdeM
Strongest in
Java · C# · SQL · Cloud & Infrastructure
Based in
Montréal, QC
Languages
English · French · Arabic

Experience

  1. Mar 2026 to Present

    Software Developer

    I moved the client's site off WordPress onto a PHP content platform I wrote for them. It handles uploads, keeps an activity log that only ever appends, and keeps a version history per document, so a change can be traced back later. Compressing images on the server cut page weight by 45%. I am the only technical person there, so the deploys and content releases are mine too, and I wrote down the steps so they could stop calling me for routine changes. The newsletter automation came out of that work: Python and JavaScript across three languages, which took a one to three hour job down to about thirty minutes over more than ten campaigns.

  2. May 2022 to Feb 2024

    Gatestone

    Montréal, QC

    Technical Support Representative

    I diagnosed connectivity and account problems for enterprise clients, under time pressure. Every call started with identity verification before I could touch sensitive data.

Selected projects

5 projects

Three I would want to be asked about, then the rest. One of them runs live on this page.

uiResidentMenu · IntervenantMenuOpenDataSourceinterfaceMontrealOpenDataHTTP · CKANJSON fixtures35 offline testsdonnees.montreal.ca
The seam the refactor introduced: the console screens depend on an OpenDataSource interface. MontrealOpenData implements it over HTTP against the city's CKAN portal; the tests implement it from JSON fixtures, so the suite runs offline.

Java application

2026

My City

A Java app that lets Montréal residents look up the roadwork happening on their street, and lets contractors find and bid on the work people file.

The city publishes all of it as open data, and none of it is readable by a person. I took a working team project and made it something another developer could actually pick up.

  • Moved the build to Maven so a fresh clone compiles. Before that it only built inside the IDE we wrote it in.
  • Split two very large classes into smaller ones, taking Resident.java from 780 lines to 106 and Menu.java from 579 to 97.
  • Found and fixed 6 bugs while removing duplicated code, and grew the test suite from 9 tests to 35.
  • Java 17
  • Maven
  • JUnit 4
  • Gson
  • REST / JSON
  • Montréal open data
What splitting a 780-line class turned up
Resident.java
780 → 106 lines

The screens, an HTTP client, JSON parsing and the Scanner reads came out. What is left is a person's seven fields and the two operations that belong to them.

Menu.java
579 → 97 lines

Both sign-in screens, both registration screens, both post-sign-in menus and five input validators came out. It now picks between signing in and registering.

Test suite
9 → 35 tests

Across 6 files, from 3. The old suite needed a live third-party API to pass; mvn test now needs neither a network nor a terminal.

Duplication defects found
6

Each one surfaced while collapsing copies of the same code. Listed in the commit that removed them.

Three of us built this for a course and it worked fine on our machines. That was the problem. JUnit and Hamcrest were committed as jar files, and Gson came in through an IntelliJ setting that pointed at a folder on somebody's laptop. Anyone else who cloned it got a wall of errors. Moving it to Maven was the first thing I did.

The part I found most interesting was splitting up Resident.java. It was 780 lines and doing about five jobs at once: holding a person's details, drawing the screens, calling the city's API, parsing the JSON and reading the keyboard. I pulled the network and parsing code into its own package and the screens into another. Doing that turned up a bug I liked. The list of ten work categories existed in three separate copies that had drifted apart, so option 8 read "Travaux résidentiel" on one screen and "Travaux résidentiels" on another. A resident could file a request and then never find it again. It is one enum now, with a test that fails if the labels stop matching.

Most of the bugs I found came from the same cause: the same logic written out more than once. The other thing I took away is that separating the code that fetches from the code that parses is what let the tests run without a network. The old suite had one test that called the live city API, so the build failed on any machine that could not reach it.

watcher repoprivate · scheduledETag · 304job boards421 trackeddedupe · score 0-100 · work-auth parsereasons kept on every scoredata repopublic · jobs + healthCORSdashboardstatic Reactno server between the sweep and the browserfreshness published, so a dead sweep is visible
Four stages. A private scheduled repository holds the schedule and the filters and runs the sweep. The sweep fetches job boards with ETags, then deduplicates, scores and parses work authorization. It writes JSON to a separate public data repository. A static React dashboard reads that JSON in the browser over CORS, with no server in the path.

Automation & data pipeline

2026

Job Watcher

A tool that checks hundreds of job boards on a schedule, ranks what it finds against my profile, and shows it on a page that costs nothing to run.

Good roles close in days. Checking a wall of boards by hand every morning is a chore, and chores get dropped. Then you find out a role existed a week after it closed.

  • Used AI-assisted coding for most of the implementation. I wrote the specs and the JSON format the pieces share, then reviewed, tested and debugged what came back.
  • Set it up in three parts: a private repo runs the schedule, a public repo holds the JSON output, and a static page reads it in the browser. Nothing runs on a server.
  • Currently tracking 421 boards and showing 442 scored roles across 268 companies, with the reasons for each score kept alongside it.
  • System design
  • Scheduled automation
  • GitHub Actions
  • JSON data contracts
  • ETag caching
  • CORS
  • TypeScript
  • React
The pipeline, the contract, and who decided what
Boards tracked
421

boards_known in the live health.json the sweep publishes. Read it yourself; the data repository is public.

Roles in the current feed
442

Across 268 distinct companies, after deduplication, scored and ranked. Counted from the live jobs.json.

Upstream postings scanned
3,331

last_count from the most recent sweep. Fetched with an ETag, so an unchanged source costs one 304 and no parsing.

Dashboard refresh
120 s

The page re-reads the feed on a timer. Every request is cache-busted, since the CDN sends max-age=300 and a five minute cache would undo the point of the tool.

I got tired of checking job boards by hand every morning, so I built something to do it on a schedule. I used AI-assisted coding for most of the implementation. What I did myself was decide how the pieces fit together, write a short spec for each one, and settle the JSON format they pass between them before any code existed. Then I reviewed what came back, tested it, and fixed what was wrong. Being able to read and debug that code is the part that matters to me.

It is in three parts. A private repo holds the schedule and my filters and runs the fetch. A public repo holds nothing but the JSON it produces. A static page reads that JSON straight from the browser. There is no server anywhere in it, which keeps it free to run and means there is nothing to keep alive.

The failure I did not anticipate is a scheduled job that quietly stops. It does not warn you. It keeps showing whatever it fetched last and looks completely normal, and you notice a week later. So every run now records when it ran and which sources answered, and the page shows how old the data is. I also learned how ETags work while building the fetch step: if a board has not changed since last time, it answers 304 and there is nothing to download or parse.

containersentinelPID 1 · subreaper./appown process groupfork · execorphanadoptedreapeddocker stopSIGTERMkill(-pgid)still alive after 5s, then SIGKILLexit status: the child's own, or 128 + N
Process supervision inside a container: sentinel runs as PID 1, forks and execs the application into its own process group, forwards an incoming SIGTERM to that whole group and escalates to SIGKILL after five seconds, adopts and reaps orphaned descendants, and exits with the child's own status.

Linux & containers

2026

sentinel

A small program that sits inside a Linux container and makes sure the app shuts down cleanly when it is told to, without leaving stray processes behind.

Containers get ten seconds to stop before they are killed outright. An app that never handles the stop signal spends all ten of them ignoring it, then loses whatever it was in the middle of.

  • Handles the stop signal so the container exits in about 3 ms. Left alone, the same program ignores it and gets killed at the 10 second mark.
  • Restarts a child that dies, waiting 1, 2, 4, 8 then 16 seconds between attempts, and counts restarts and crashes for Prometheus to read.
  • Wrote 13 tests and 5 CI jobs. CI starts the whole Docker Compose stack and fails if Prometheus is not collecting or Grafana has no dashboard.
  • C++17
  • Linux
  • POSIX signals
  • Docker Compose
  • Prometheus
  • Grafana
  • GitHub Actions
What PID 1 costs you
Shutdown after SIGTERM
2.5 to 3.1 ms

Seven runs against a worker supervised by sentinel, timed by waiting on the process. The same worker on its own was still alive at the ten second mark and had to be killed.

Child that ignores SIGTERM
5.003 s

Same setup with the worker deliberately ignoring the signal. Three runs, all within 1 ms of each other. That is the five second timeout doing its job.

Test suite
13 of 13

ctest on a release build, 33 s. CI runs build, test, shellcheck, docker and compose as separate jobs.

I wanted to understand what actually happens when a container is told to stop. Docker sends SIGTERM and waits ten seconds before killing it. Linux treats the first process in a container as a special case and will not deliver a signal to it unless that process has installed a handler, so a program sitting in that slot spends the whole ten seconds ignoring the request and then dies mid-work. sentinel takes that slot, passes the signal on to the real program, and gets out of the way.

The bug I spent the longest on was a gap between starting the child process and installing the handlers. A stop signal arriving in that window killed sentinel and left the child running loose, which is the exact thing the program exists to prevent. I knew about it for a while and left a TODO on it before working out that blocking those two signals across the start and unblocking them once the handlers were up closes the window.

A lot of this project was reading manual pages and then testing whether I had understood them. The thing that stuck: measuring is harder than it looks. My first shutdown number was ten times too high because I was checking in a polling loop and reading my own delay. Waiting on the process properly gave the real figure.

More projects

  • Mutation Testing in CI for GraphHopper

    2025

    A check added to an open-source routing engine's build that measures whether its tests would actually catch a bug, and fails the build when that gets worse.

    JavaPITMockitoMavenGitHub Actions
  • Neural Network & Hyperparameter Study

    2026

    A small image classifier written from scratch in NumPy, compressed to 55 KB so it runs in your browser on this page.

    PythonNumPyPyTorch

Skills

Languages
  • Java
  • SQL
  • C++
  • Python
  • Bash
  • PHP
  • C
  • Zig

Used in: Every project here, and the Crono Design work

JVM & data
  • Java 17
  • Maven
  • JUnit & Mockito
  • Spring Boot
  • Spring Data JPA
  • REST APIs
  • PostgreSQL schema design

Used in: My City · Mutation Testing in CI

Reliability & operations
  • Graceful shutdown
  • Restart policy & backoff
  • Runbooks & handover docs
  • Audit logging
  • Incident debugging

Used in: sentinel · six months as the only technical person at Crono Design

CI/CD & deployment
  • GitHub Actions
  • Multi-job pipelines
  • Merge gating
  • Docker
  • Multi-stage builds
  • Docker Compose
  • Nginx

Used in: sentinel · Mutation Testing in CI · My City

Observability
  • Prometheus metrics
  • Text exposition format
  • Counters & gauges
  • Alert rules
  • Grafana dashboards

Used in: sentinel, where CI fails unless the stack really scrapes

Linux & systems
  • Processes & signals
  • fork / exec / wait
  • Process supervision
  • Concurrency
  • Manual memory management

Used in: sentinel · Three Allocators in Zig · Fedora daily driver

Tooling
  • Git
  • GDB
  • strace
  • CMake
  • ctest
  • Make

Used in: Refactoring My City · building sentinel

Recognition

DIRO Excellence Scholarship2024
The computer science department at Université de Montréal awarded it for academic standing.
Top 30 at the NorthSec CTF2025
My team placed in the top 30 of roughly 93 teams at the largest applied-security competition in North America.

About

Montréal, QC

For six months I've been the only technical person on a client's web presence. I handle the hosting, the deploys and the content releases. I wrote the runbook so they could stop calling me for routine changes. It's unglamorous work. I learned more about reliability from it than from anything else I have built.

The questions that keep me busy are the ones a framework does not answer for you. What is the first process in a container actually responsible for? Why can a test suite be green and still miss real bugs? I tend to pick a project because I want to find out, and I usually learn the most from the part that goes wrong.

Up next

My City keeps everything in memory, so a restart loses it. The next piece is Postgres behind that store.

Contact

What I would like to work on

Backend work, mostly: Java services and the data behind them, containers and deployment, and build pipelines. I am happiest on a team where I can ask questions and see how people more experienced than me approach a problem.

tarik.hireche@umontreal.ca
Résumé
PDF