Swift Academy Podcast · Series

A mock-interview series with Artem Mirzabekian, Lead iOS Engineer. Real mobile system design problems, solved out loud the way a senior interview actually runs, with the roles swapping between episodes. Two episodes published.

🎧 Swift Academy Podcast · Series · 2 episodes · Requirements • APIs • Domain • Architecture

“Most system design conversations stop at the box diagram. The interesting part starts after: what happens when the cursor is stale, the receipt URL has expired, and the user is on a train with no signal.”

The premise of this series

What This Series Is

Mobile system design is usually taught as a whiteboard ritual, or reduced to an argument about architectural acronyms. This series does the opposite. Each episode takes one realistic feature and designs it properly, out loud, with the trade-offs left visible instead of tidied away. Episode 1 tackles an e-commerce home page; episode 2, broken down below, tackles the transaction history of a banking app.

The feature is deliberately unglamorous and deliberately hard. A transaction list looks trivial until you hold it to production standards: thousands of records, a server that keeps changing beneath you, a search field, filters, receipts behind expiring URLs, and a security team with a firm opinion about what may be written to disk. Every decision in it has a cost, and the point of the series is to name that cost rather than hide it.

Inside Episode 2: Designing a Transaction History

Paging Through a List That Will Not Sit Still

Offset pagination breaks the moment records are inserted while the user scrolls: rows repeat, rows vanish, and nobody notices until it reaches production. Cursor-based pagination is the answer, and the design work is in the details around it.

  • Why offset paging is unsafe against a mutating dataset, and what the user actually sees when it fails
  • Cursor design: opaque tokens, stability guarantees, and what to do when the server invalidates one mid-scroll
  • Prefetch thresholds, in-flight request de-duplication, and cancelling work the user has scrolled past
  • Where the cursor lives, and why it does not belong in the view

Search and Filter Without Fighting the Pagination

Search and filters are where a clean pagination design usually falls apart, because each one produces a different result set with its own cursor and its own lifecycle.

  • Server-side versus client-side filtering, and the point where the dataset makes the choice for you
  • Debouncing, cancellation, and keeping the visible list coherent while a query is in flight
  • Composing filters, date ranges, categories, amounts, without a combinatorial explosion of endpoints
  • Resetting or preserving scroll position when the query changes

States and Freshness

“Loading, loaded, error” is not a state model, it is a placeholder for one. Real screens are simultaneously stale, refreshing, partially loaded, and partially failed.

  • Modelling loading, empty, partial, stale, refreshing and failed as a type the compiler can check
  • Distinguishing an empty list from a list that has not loaded, the single most common bug in this feature
  • Freshness policy: what to show immediately from cache, what to revalidate, and what to block on
  • Error recovery that does not discard the data the user is already reading

The Offline Versus Security Debate

This is the part of the series with no clean answer, which is exactly why it is worth recording. Offline access argues for caching transactions on device. The security posture of a banking app argues against writing financial history to disk at all.

  • The real threat model: device theft, backups, jailbreak, shared devices, and what each one actually exposes
  • What a partial answer looks like, caching metadata but not amounts, or encrypting with a key held in the Secure Enclave
  • Cache lifetime tied to session lifetime, and what must be destroyed at logout
  • Why this decision belongs to the product and the security team, and what the architecture must do to keep it reversible

Expiring Receipt URLs

Receipts are served behind short-lived signed URLs. That single constraint reaches surprisingly far into the design.

  • Why a signed URL must never be persisted, and what to persist instead
  • Fetching the URL lazily at the moment of use, and handling expiry between tap and load
  • Retry and re-signing flows that do not strand the user on a broken screen
  • What this implies for share sheets, deep links, and anything that outlives the session

SwiftUI, UIKit, and the Layers Underneath

The UI framework is the least interesting decision on this list, and the one people argue about most. We treat it as an implementation detail and spend the time on the layering that survives either choice.

  • Where SwiftUI is a clear win for this screen, and where UIKit still holds an advantage on large lists
  • Interoperating deliberately rather than accidentally, and keeping the boundary in one place
  • ViewModel, Presenter, Service, UseCase: what each layer owns, and the concrete test you apply to decide where a piece of logic belongs
  • Keeping the pagination, freshness and caching policy testable without a running UI

What This Series Deliberately Avoids

  • No MVVM versus VIPER debate. It is a distraction from system design. We talk about responsibilities and boundaries; name the resulting pattern whatever your team already calls it.
  • No whiteboard theatre. Every decision is tied to a failure mode you can actually observe in a shipped app.
  • No single right answer. Where the trade-off is genuine, it is left as a trade-off, with the cost of each side stated plainly.

About the Guest

Artem Mirzabekian

Lead iOS Engineer at Sovcombank • 10+ years scaling mobile platforms

Artem leads iOS engineering at Sovcombank, where transaction history is not a hypothetical exercise but a screen used by millions of customers under real regulatory and security constraints. His work spans iOS architecture, Swift, SwiftUI, system design and technical leadership, with a decade of experience scaling mobile platforms and the teams that build them.

Watch the Series

Episode 1, Designing an E-Commerce Home Page

The opening episode takes one of the most common mobile engineering scenarios and runs it as a real interview: clarifying requirements, defining the APIs and data models, and arriving at an architecture that scales. Artem published a companion repository with a working implementation of the ideas discussed, typed backend-driven sections, defensive DTO mapping, cache-first loading, visibility-based analytics, optimistic add-to-cart, and an image pipeline with downsampling and request de-duplication.

Episode 2, Designing a Banking Transactions Screen

The second episode swaps the roles: this time Walid is the candidate and Artem the interviewer. It is the session the breakdown below is drawn from, working through the transaction history of a mobile banking application from requirements to architecture.

Go Deeper: AI-Driven Swift Architecture

The layering this series relies on, use cases, services, and the boundaries that keep a feature testable, is the subject of the book. If the sessions leave you wanting the full treatment of Clean Architecture, TDD and modular Swift on production codebases, that is where to continue.