You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Address Adham's feedback: role accuracy and narrative flow
Adham (founding engineer on Statsbomb project) provided critical feedback:
1. Role title inaccurate - was "Principal" (oversight), should be "Founding" (building from zero)
2. Code examples broke narrative flow even in collapsible accordions
Changes:
- Update role to "Founding Engineer leading data collection system" (case study + resume)
- Remove ~160 lines of DSL/JavaScript code, replace with conceptual narrative
- Add Socratic questions to section headings (writing guideline compliance)
- Soften bold claims with context and humility ("prevented" → "reduced", acknowledge edge cases)
- Enhance collaborative framing ("I didn't want" → "we were protective")
- Regenerate resume PDF with corrected title
Result: More accurate role representation, improved narrative flow, better tone alignment with philosophical humility guidelines.
<Headinglevel={2}as="h2"class="mb-6">Problem: How Do You Scale Without Choosing Between Speed and Correctness?</Heading>
64
63
65
64
Week one. Ali and I sat down with paper. We hand-wrote sequencing rules for soccer matches—which events could follow which, what validated as legal, how phases transitioned. It was painful. But necessary.
66
65
@@ -112,128 +111,9 @@ We separated three concerns: **entry validation** (dataspec), **sequencing logic
112
111
(DSL), and **aggregation rules** (grouping DSL). Product managers wrote rules in readable
# When: Offensive drive ends with touchdown or field goal
228
-
# Derive: scoring-drive
229
-
Derive event scoring-drive from events sequence:
230
-
- offensive-drive team mine
231
-
then touchdown team mine OR field-goal field outcome is good team mine
232
-
```
233
-
234
-
</Accordion>
114
+
The DSL let product managers define domain logic as sequences and dependencies. For soccer, they could express that possession meant a team had active carry (player dribbling), received fouls, or forced the ball out—spans of time aggregated from atomic events. Individual passes became complete-pass metrics. Multiple dribbles by the same player became a carry. Turnovers derived from possession changes. The rules formed dependency layers: atomic events (passes, shots), player-level facts (carries), team-level aggregations (possession), and higher-level derivatives (turnovers).
235
115
236
-
When we expanded to American football, product managers wrote new dataspecs and grouping rules.
116
+
When we expanded to American football, product managers wrote drive segmentation rules using the same DSL patterns. Offensive drives derived from snap sequences until scoring or turnover. Red zone conversions tracked touchdown efficiency. Third-down success measured possession maintenance. The execution engine didn't change—new sport, same architectural separation. No engineering bottleneck.
237
117
238
118
<Accordionsummary="Visualizing the Data Flow"class="mb-6">
239
119
@@ -384,68 +264,15 @@ graph TD
384
264
385
265
**State Machines for Impossible States**
386
266
387
-
We used XState to model collection workflows as explicit finite state machines. Traditional event handlers create implicit state explosions (`if (editing && !watching && hasBase)`). State machines make all transitions explicit and testable.
Five major state machines orchestrated the app: main room, event entry, player customization, freeze frame queue, and batch validation. This prevented illegal states by design—you couldn't enter a freeze frame without an active event, couldn't submit without required fields.
403
-
404
-
<Accordionsummary="30+ Keyboard Shortcuts: Muscle Memory Over Mouse Clicks">
405
-
406
-
We used Mousetrap with module scoping. Same key, different action per context:
We used XState to model collection workflows as explicit finite state machines. Five major state machines orchestrated the app: video mode (manual playback, loop, editing), collection flow (watching, collecting base event, adding details), freeze frame handling (idle, active, reviewing), player customization, and batch validation. This prevented illegal states by design—you couldn't enter a freeze frame without an active event, couldn't submit without required fields. In our context, traditional event handlers created implicit state explosions—tracking state across event handlers made correctness fragile. State machines helped us make transitions explicit and testable, though this added complexity that only paid off at scale.
428
268
429
-
Collectors touch-typed events like Vim users touch-type code. Video control (arrow keys), event creation (letter keys), navigation (/, Z), editing (Shift+E), freeze frames (number keys). Hands stayed on keyboard. Eyes stayed on video.
430
-
431
-
</Accordion>
269
+
**30+ Keyboard Shortcuts: Muscle Memory Over Mouse Clicks**
432
270
433
-
<Accordionsummary="Contextual UI Adaptation">
271
+
Contextual keyboard mappings with module scoping meant the same key could trigger different actions depending on context. In the main collection view, `t` created new events (pass, shot, tackle), `/` toggled video loop mode, and arrow keys controlled playback. In freeze frame mode, `t` toggled team view, number keys selected players by jersey, Enter confirmed positions. Collectors touch-typed events like Vim users touch-type code. Hands stayed on keyboard. Eyes stayed on video.
434
272
435
-
The interface adapted based on game state and previous decisions. When a collector selected "Pass," the system showed only valid pass types for that player's position. Auto-filled mandatory fields with single valid options. Skipped irrelevant choices entirely.
273
+
**Contextual UI Adaptation**
436
274
437
-
```javascript
438
-
// After DSL sequence rules run and determine valid next options
439
-
// If only one option remains valid, auto-fill and skip the question
440
-
// Example: "Pass" event followed by rules determining only "Reception" is valid → auto-fill
441
-
if (hasOnlyOneValidOption(currentField, validOptions)) {
Cognitive load minimization: collectors never saw irrelevant options.
447
-
448
-
</Accordion>
275
+
The interface adapted based on game state and previous decisions. When a collector selected "Pass," the system showed only valid pass types for that player's position. DSL sequence rules determined valid next options. If only one option remained valid, the system auto-filled and skipped the question entirely. Cognitive load minimization—collectors never saw irrelevant options.
449
276
450
277
<Accordionsummary="Video Loop Mode">
451
278
@@ -459,14 +286,14 @@ Freeze frames (positioning data for all 22 players) were semi-automated. Collect
459
286
460
287
</Accordion>
461
288
462
-
This tool became the foundation. The dataspec drove UI validation, the DSL defined legal event sequences, the state machines enforced correctness. Concurrent collection during live matches with sub-minute latency. The backend scaled to support what the UX tool showed collectors needed.
289
+
This tool became the foundation. The dataspec drove UI validation, the DSL defined legal event sequences, the state machines constrained invalid states. We still found edge cases in production, but the architecture caught most errors before they reached collectors. Concurrent collection during live matches with sub-minute latency. The backend scaled to support what the UX tool showed collectors needed.
463
290
</div>
464
291
465
292
{/* Event Collection Subsection */}
466
293
<divclass="mb-10">
467
294
<Headinglevel={3}as="h3"class="mb-4"><span>Backend Evolution: From Batch to Real-Time</span></Heading>
468
295
469
-
Breaking matches down by decision rather than team increased correctness without additional effort. Computer vision assisted input, contextual keyboard mappings reduced cognitive load, and automated linting caught preventable errors. Collectors focused on judgment over correction—handling edge cases where human expertise mattered rather than catching mistakes.
296
+
Breaking matches down by decision rather than team increased correctness while reducing collector coordination overhead. Computer vision assisted input, contextual keyboard mappings reduced cognitive load, and automated linting caught preventable errors. Collectors focused on judgment over correction—handling edge cases where human expertise mattered rather than catching mistakes.
team (emerald) resolves ambiguity. Golden entities cascade updates to dependent systems automatically.
630
457
</Body>
631
458
632
-
The system prevented duplicate entities by design, caught conflicts automatically, and escalated true ambiguity. The 5-person team focused on the 1-2% of ambiguous cases requiring domain expertise (is "FC Barcelona" the same as "Barcelona FC"? yes; but "Manchester United" vs "Manchester City"? no).
459
+
The system's design reduced duplicate entities, caught most conflicts automatically, and escalated true ambiguity. The 5-person team focused on the 1-2% of ambiguous cases requiring domain expertise (is "FC Barcelona" the same as "Barcelona FC"? yes; but "Manchester United" vs "Manchester City"? no).
633
460
</div>
634
461
</section>
635
462
636
463
{/* Impact Section */}
637
464
<sectionclass="mb-16">
638
-
<Headinglevel={2}as="h2"class="mb-6"><span>Impact: From Bottleneck to Multiplier</span></Heading>
465
+
<Headinglevel={2}as="h2"class="mb-6"><span>Impact: What Changed When Architecture Met Distributed Ownership?</span></Heading>
Design for the 80% common case; production iteration reveals the 20% edge cases.
@@ -653,7 +480,7 @@ ambiguous data points—rather than catching preventable mistakes.
653
480
654
481
**Non-linear leverage:** Operations scaled 10x without proportional staffing increases.
655
482
656
-
The system scaled horizontally. Product managers shipped features.
483
+
The system scaled horizontally as load increased. Product managers could ship new dataspecs without engineering bottlenecks, though some edge cases still required technical collaboration.
657
484
658
485
</Accordion>
659
486
@@ -684,7 +511,7 @@ Month one backend: a single Go endpoint called `sync`—batch, offline. We start
684
511
685
512
<Accordionsummary="Years Two-Three: Scaling from Partnership to Distributed Team"class="mb-6">
686
513
687
-
Adham and I could execute together, but the domain kept expanding. The transition from two-person partnership to distributed team took longer than it needed—I was learning how to lead engineers while building production systems. The tension: I didn't want to compromise on the architectural ideas the domain required, but keeping that thinking between just us became a bottleneck. Every new subsystem, every architectural decision, required our direct involvement.
514
+
Adham and I could execute together, but the domain kept expanding. The transition from two-person partnership to distributed team took longer than it needed—I was learning how to lead engineers while building production systems. The tension: we were protective of architectural integrity while the domain kept expanding, and limiting that thinking to just us became a bottleneck. Every new subsystem, every architectural decision, required our direct involvement.
688
515
689
516
By year three, we had built the hiring and mentoring systems needed to scale beyond the core partnership.
690
517
@@ -753,7 +580,7 @@ Architecture shapes what's possible. But people make it real.
753
580
754
581
{/* Lessons Section */}
755
582
<sectionclass="mb-16">
756
-
<Headinglevel={2}as="h2"class="mb-6"><span>Lessons: Context Shapes What Works</span></Heading>
583
+
<Headinglevel={2}as="h2"class="mb-6"><span>Lessons: What Transfers? What Only Worked Here?</span></Heading>
<Bodysize="sm"as="p"class="text-neutral">Bath, UK | 03/2018 - 03/2022</Body>
102
102
</div>
103
-
<Bodysize="sm"as="p"class="mb-4">Led core data infrastructure for football analytics platform—serving Premier League clubs, international federations, and media companies.</Body>
103
+
<Bodysize="sm"as="p"class="mb-4">Built core data collection system from scratch for football analytics platform—serving Premier League clubs, international federations, and media companies.</Body>
104
104
<Bodysize="base"as="ul"class="space-y-3">
105
105
<li><strong>Designed domain-specific language (ANTLR grammar) enabling product managers to define sports rules as configuration.</strong> Topological dependency resolution compiled declarative sequences ("pass then reception") into validation logic. Expanded from soccer to American football with zero code changes. Pattern: Separation of rules from execution unlocked non-linear scaling (100 → 1000+ collectors without proportional engineering).</li>
106
106
<li><strong>Built collaborative collection system (Electron + XState + Apollo GraphQL) replacing 16-hour sequential workflows with 4-hour concurrent collection.</strong> XState state machines prevented illegal states by design—collectors couldn't submit without required fields, couldn't enter freeze frames without active events. 30+ contextual keyboard shortcuts (Mousetrap with module scoping) built muscle memory—same key, different action per context.</li>
0 commit comments