Skip to content
View kutsibalci's full-sized avatar

Highlights

  • Pro

Block or report kutsibalci

Block user

Prevent this user from interacting with your repositories and sending you notifications. Learn more about blocking users.

You must be logged in to block users.

Maximum 250 characters. Please don’t include any personal information such as legal names or email addresses. Markdown is supported. This note will only be visible to you.
Report abuse

Contact GitHub support about this user’s behavior. Learn more about reporting abuse.

Report abuse
kutsibalci/README.md
Hüseyin Kutsi Balcı — Backend Development Student, Anadolu University

Backend development student at Anadolu University, based in İzmir, Türkiye. I build server-side systems end to end — schema first, then the API, then the container it ships in.

Most of what is here started as something I wanted to understand rather than something I was told to build: how an ORM actually maps a schema, what a request touches between the route and the database, what it takes to run a service on a server instead of a laptop.

Open to internships, junior backend roles and open-source collaboration.


Open Source

Five contributions merged into projects I had no prior connection to — CERN's ROOT, .NET runtime, the Rust project's GCC codegen backend, systemd, and Eclipse S-CORE.

root-project/root#23002tmva/tmva/inc/LinkDef5.h had been unreachable since 2015. The commit that split TMVA into libTMVA and libTMVAGui dropped that file's #include from the master LinkDef but left the file itself in the tree, and two later maintenance sweeps edited it without noticing it was already dead. I traced the commit that orphaned it, checked that every symbol it declared was already covered by the module that actually owns those classes, and confirmed against the generated build graph that nothing referenced it — then proposed the removal.

dotnet/runtime#131865 — eight documentation links whose targets exist but whose relative paths resolve nowhere. The one I liked was in the datacontracts design docs: they link to contract_descriptor.md while the file is contract-descriptor.md, and the same document links to it correctly twice elsewhere. So it was an inconsistency inside one file rather than a rename nobody finished. Another was written with Windows backslashes. The repository has no markdown link checker in CI, which is why they rotted quietly.

rust-lang/rustc_codegen_gcc#945 — I found these while sweeping rust-lang/rust, and the useful part was working out that I was in the wrong repository. compiler/rustc_codegen_gcc is a subtree synced from its own project, so a fix landed upstream would have been overwritten on the next sync. One link pointed at ./doc/gimple.md from a file already inside doc/. The other pointed at a file deleted a year earlier; I traced the commit that removed it and found the content had survived inside a broader debugging.md, so the entry could be repointed instead of dropped.

systemd/systemd#43300 — seven cross-references naming a man page that exists but giving a section it is not installed in, so man sends the reader to the wrong place. I resolved every <citerefentry> in man/ against man/rules/meson.build, which is generated and is therefore the authoritative list of what ships, and reported only references whose target is shipped under a different section — the section is a fact, not a judgement. The part I would defend in review is what happened next: CI went red. Rather than call it flaky, I pulled the 5.4 MB job log and found test-fiber timing out on ppc64le with Ok: 1779, Fail: 0 — nothing failed, one thing did not finish, and a change to six XML files cannot reach it. I said so, and said plainly that I could find no prior report of that timeout. Two core maintainers merged it hours later, with the job still red.

eclipse-score/communication#853 — four links in the design docs of the BMW/Bosch/Mercedes automotive platform. Three used one ../ too many; one image URL was written hhttp://, so a PlantUML diagram had never rendered. The sibling diagram in the same file already used the correct form, which is what turned a guess into a check.

The two I am most interested in are not documentation.

apache/kafka#23098TokenInformation, the delegation-token class, compares six fields in equals() and hashes seven in hashCode(). The extra one is expiryTimestamp, which equals() leaves out on purpose: renewing a token does not make it a different token. So two instances can be equal and hash differently, which is the one thing Object.hashCode forbids — HashSet keeps both, HashMap.get returns null. It is also the class's only non-final field and has a public setter, so an instance's hash changes while it sits in a collection. I walked all 500 classes in Kafka's main source that declare both methods; this is the only one where hashCode reads a field equals ignores. The test I added fails three of its four cases on trunk and passes with the fix.

eclipse-score/baselibs#444 — placement new over a live member without ending its lifetime, in ISO 26262 ASIL-B code. The issue listed three sites; a sweep found six. I did not apply the fix the reporter proposed — static_asserts showed score::Result<Value> is move-constructible but not move-assignable for the non-assignable types the code exists to support, so their suggestion would not compile. The placement new is a deliberate workaround; only the lifetime was wrong. Assigned to me by an ETAS (Bosch) engineer and queued for review by a five-person panel that includes two from BMW.

Also open: twenty links in Apache Airflow that 404 because they cross a symlink — the files open fine locally, but Git stores the directory as a symlink blob and GitHub will not traverse it (approved, awaiting merge); sixteen in NVIDIA/CUTLASS left behind by a docs reorganisation; ROOT #23004 and #23019; a bare-except fix and an issue in NASA's F´ flight software; two stale paths in the LLVM docs; and ROOT #23036, three settings shipped in system.rootrc that nothing reads — one of them documented in two places while loopback binding is actually controlled by a file-static variable.

What I keep relearning here: the patch is the easy part. Proving the claim before making it is the actual work. Those eight .NET links came out of thirty-nine candidates and the twenty in Airflow out of three hundred and seventy-two; in CUTLASS, ten "broken" links turned out to work because GitHub rewrites a leading slash to the repository root — I only learned that by fetching the rendered page instead of trusting my reading, and fourteen more were pointer values in sample output that happen to match the markdown link grammar exactly. At systemd I compared thirteen config parser tables against their man pages and found nothing: every mismatch was a deliberate compatibility alias or a page shared by xi:include. A sweep that finds nothing is a result too, and one that finds plenty is usually wrong. Several findings I was sure about never left my machine.


Featured — Concurrent Ticketing

concurrent-ticketing — a ticketing API built around one question: what stops the same seat from being sold twice?

Two customers open the same event page and click seat A12 in the same millisecond. The obvious implementation reads the seat, sees Available, and writes Held — and so does the other request, because both read before either wrote. Nothing is wrong with either line; the bug lives in the gap between them, and it only shows up under load.

The fix is to make the check and the write one statement. Seat maps PostgreSQL's xmin system column as an EF Core concurrency token, so the write carries the version the read saw:

UPDATE seats SET status = 1 WHERE id = @id AND xmin = @version;

The first transaction to commit changes xmin. The second matches zero rows and gets a 409 instead of overwriting a sale. No table locks, no SELECT FOR UPDATE, and two customers buying different seats never contend.

Measured rather than asserted — twenty concurrent requests, one seat, real PostgreSQL in a container:

20 concurrent requests → 1 × 201 Created, 19 × 409 Conflict
database: 1 held seat, 1 reservation

The second race is telling anyone about it. Confirming a reservation writes to PostgreSQL and publishes to RabbitMQ, and no transaction spans both — publish first and the broker may hold an event for a commit that fails; publish after and the process can die in between. So the event is written as a row in the same transaction as the reservation, and a dispatcher moves it to the broker afterwards. That is at-least-once rather than exactly-once, and the consumer absorbs the difference: a receipt row keyed on the message id, inserted alongside the work, so a duplicate delivery hits the primary key instead of sending a second e-mail.

FOR UPDATE SKIP LOCKED is what lets a second dispatcher be started at all — FOR UPDATE alone would make it queue behind the first.

The tests I value most here are the ones added last. With 84 passing, running the stack by hand showed POST /api/auth/register accepting a three-character password and the literal string bu-bir-email-degil as an e-mail address: the contracts carried [Required] and [MinLength], but nothing evaluated them, and no test crossed the HTTP boundary where they live. A green suite says the tested thing works. It says nothing about the untested one.

.NET 10 · PostgreSQL · RabbitMQ · Redis · JWT with refresh rotation · Clean Architecture · Testcontainers · 119 tests · Docker Compose · CI


What testing an old project taught me

Course Registration System architecture

Course Registration System — an ASP.NET Core MVC application that worked. Adding tests to it was supposed to be a formality: writing down behaviour that already held.

Several of the first tests failed.

Finding What it meant
AdminController had no [Authorize] The whole management area answered anonymous requests — POST /Admin/KursSil deleted a course with no session at all
Administrator credentials were string literals The working password shipped with the source
Passwords stored in clear text Reading the database was reading every password
Cancellation never checked ownership Any signed-in student could cancel anyone else's place by incrementing an id
Capacity was a read-then-write race Counted, compared, then inserted

The last one is the one worth measuring. Reproducing the original logic under 15 concurrent applications to a course with capacity 5:

old logic (count → compare → insert):   15 enrolled     ← 3× over capacity
current logic (conditional UPDATE):       5 enrolled

62 tests now, and CI that fails the build on any dependency with a known advisory.

The same read-then-write shape turned up in the coffee shop till, and I only found it because I was trying to make the ordering logic testable. Adding the first item to a table read the table's state, saw it free, then opened a tab — so two waiters on two terminals both read free and both opened one. The order screen only ever shows the newest tab, so everything written to the other was never billed. One conditional UPDATE closes it, the same way the course capacity was closed. Third time I have written that fix now; I have stopped thinking of it as a trick and started looking for the shape.


Also Building — File Analysis Service

File Analysis Service architecture

A pipeline that scans uploads with YARA rules, parses PE structure with pefile, and submits samples to a CAPE sandbox. Work is queued through Redis to a Celery worker rather than blocking the request — analysing an untrusted file is slow, and it has no business happening inside an HTTP handler.

The lesson that stuck came from a bug in my own code: YARA compile errors were caught by a bare except and skipped, so a rule file with a syntax error made every sample come back clean. For a scanner, no findings and the scan never ran look identical from the outside, and only one of them means the file is safe. A crash is a good outcome; a false negative is the bad one.


Focus

Area What I'm actually doing about it
Concurrency Optimistic concurrency against a real database, and tests that genuinely race rather than asserting they would
Messaging Transactional outbox, at-least-once delivery, idempotent consumers, dead-letter queues — RabbitMQ driven directly rather than through a framework, because the mechanics are the point
API design Paginated, validated REST endpoints — with ordering that makes pagination stable and ceilings on anything read into memory
Data modelling Normalised schemas, code-first migrations, and constraints in the database rather than only in application code
Deployment Docker Compose and AWS EC2, with credentials from the environment and nothing sensitive published on a port
Analysis tooling Static and dynamic file analysis with YARA and Celery — the area I find most interesting right now

Stack

Technology stack

Projects

Concurrent Ticketing — .NET 10, PostgreSQL, RabbitMQ, Redis Course Registration System — ASP.NET Core MVC, EF Core, SQLite
Business Directory API — FastAPI, SQLAlchemy, Alembic File Analysis Service — FastAPI, YARA, Celery, Docker
Redmine Deployment — Docker Compose, PostgreSQL, AWS EC2 Coffee Shop Management — C#, Windows Forms, MySQL
Pansuman Simulator — Unity, URP, C#

Some of this is team work — the Redmine deployment was built with Atakan MERGEN (@hzflora), whose repositories I also contribute to.


Currently Learning

  1. SQL query planning — reading execution plans instead of guessing at indexes
  2. What breaks when one service becomes several: distributed tracing, and knowing which failures a retry actually fixes
  3. Data structures and algorithms, properly rather than for exams


Get in touchbalcihkutsi@gmail.com

İzmir, Türkiye · open to remote and hybrid roles

Pinned Loading

  1. Course-Registration-System Course-Registration-System Public

    Course registration and management web app built with ASP.NET Core MVC, EF Core and SQLite - student applications, plus an admin panel for courses and instructors.

    C#

  2. Small-coffee-Shop-Management-App Small-coffee-Shop-Management-App Public

    Windows Forms point-of-sale app for a small coffee shop - order taking, table tracking and an admin panel, backed by MySQL.

    C#

  3. concurrent-ticketing concurrent-ticketing Public

    Ticketing API showing how a seat is sold exactly once under concurrent demand - PostgreSQL xmin optimistic concurrency, a transactional outbox to RabbitMQ, JWT with refresh rotation, and 119 tests …

    C#

  4. watch-party-sync-engine watch-party-sync-engine Public

    Real-time watch-together sync engine: WebSocket sync layer, atomic state transitions in Redis Lua, a hand-written job queue and an ffmpeg HLS transcoding pipeline. Horizontal scaling verified by me…

    TypeScript