Amir Balazade

Amir Balazade

Front-end engineer

abalazade@gmail.comlinkedin.com/in/amirbalazade

Istanbul, open to remote

Index

The upgrade was the cheap part

The panel the desk runs orders, customers and payouts from. Three Angular majors in one pass, zoneless, and a grid library that moved the floor underneath it.

Surface
Internal admin: orders, customers, partners, financial, support
Work
Angular 19 to 22, zoneless, ag-grid 33 to 36, standalone migration, test toolchain
Stack
Angular 22, ag-grid 36, ECharts, vitest

Ranking the cost before starting

Framework majors are mostly mechanical. What actually costs time is everything that changes meaning underneath them, so the plan opened by ranking the drivers rather than the versions.

Zoneless with OnPush by default came first: 53 components change change-detection semantics at once, around 16 of them had async paths that were repainting by luck, and the repo contained zero explicit change-detector calls to lean on while sorting that out. Second was the grid library's own major, which collapses nine or more scroll containers into one and renames the layout classes — four style overrides sat directly in that blast radius. TypeScript's major was checked and turned out to be a non-event for this configuration, which is worth measuring rather than fearing.

Two declared dependencies were imported nowhere at all. Deleting them removed a forcing function that would otherwise have dragged an error-reporting library through its own major upgrade, in service of code that did not exist.

The same problem, answered the other way

The component library that was deleted from thepayment gateway stayed here, on the registered free tier. That is not an inconsistency. The payment page used six component instances and is public; removing them was an afternoon, and refusing a third-party banner over a payment form is worth more than the afternoon. The admin panel is built out of that library across every screen, and it is internal. The cost of removal and the cost of the risk both invert, so the decision inverts with them.

Verification, and one objection on the record

Verification was a before-and-after sweep across roughly twenty routes with accessibility checks injected into the same sweep, running against a read-only proxy so the comparison used real shapes of data rather than optimistic fixtures. The test toolchain moved in the same pass, three older specs rewritten and the previous runner dropped.

The delivery decision was one squashed commit. I argued against it and was overruled, so it is recorded in the plan where the next person will find it: a grid regression, a zoneless repaint bug and a compiler error all land in one undifferentiated diff, with no CI to separate them. Losing that argument is fine. Losing it silently would have left whoever bisects it later with no idea the trade was made deliberately.

The all-orders grid with type, status and submission-time columns, and identifying columns blurred
The orders grid: server-side sort and search, infinite scroll, per-type tabs. Order and account columns are blurred here — the grid is production, and who trades with whom is not mine to publish.
The payments tab showing a loading overlay above an empty-state message
The state most grids get wrong: loading and empty are different answers, and a tab that has no rows yet should say so rather than spin forever.

The wallet, and a signature that went missing