DAMIEN ZEMANEK

Systems Portfolio

Technical Programmer - Systems Engineer


C# - SYSTEMS ARCHITECTURE - ASYNC

  • Internal middleware pipeline

  • Fuent-api step composition

  • Immutable context delivery

  • Async execution optionality

  • Explicit before/short-circuit/after resolving

Technical Programmer - Systems Engineer


C# - SYstems architecture - Unity3d

Documentation In Progress :)

Technical Programmer - Systems Engineer


Unity3d - C# - Solo Project - Miro

Documentation In Progress :)


overview

INfo

Language: C#
Team Size: 1
Time Frame: 5 weeks + Updates
Target Engine: Unity3D

Contribution

  • Built internal middleware pipeline system based off SWE middleware pattern with type-safe immutable context delivery

  • Created pipeline builder for fluent-api style step composition

  • Built separate pipeline executor adhering to SOLID principles

  • Created PipelineStep data-structure to house step type, logic, and resolution logic

  • Integrated with custom Timer system for player-loop plug and play

  • Constructed with custom SRP Resolver system for extra-specific functionality branching

  • Build NUnit and Unity TestRunner test suite

introduction & goals

  • Pipeline was my first major Systems Design project I worked on to solve an issue I had where I needed to pass immutable, readable information at a performant, fast and consistent rate. Serving as a sub-system of my larger MonoFacade system.

  • In order to design this system I went through a research phase, ideation and greybox, development, testing through developing a test suite, and integration with other systems to complete this project. I plan to continue to update this project overtime and have it as a core system apart of my EMILtools system library.

1. RESEARCH PHASE

What i did

  • Compiled releavant research videos

  • Studies concepts to understand design constraints & system purpose

  • Took notes and wrote down what I wanted to actually design in accordance with research/what I would take from the videos

2. diagram greybox phase

what i did

  • Kept in mind design constraints, greyboxed initial code flow

  • Used FIGMA to create diagrams tha representated high-level abstractions

  • Saved and iteratedon design flow when changes were made

3. development phase

What i did

  • Data structure & system design

  • Created a Pipeline<TViewCtx> data class to hold PipelineStep<TViewCtx> data structure classes to separate data handling responsibility

  • Composed PipelineStep<TViewCtx> with StepType enum, and option to either have a callback, or a predicate resolution with custom predicate classes

  • Defined a IContextViewImmutable interface to serve as a generic constraint for <TViewCtx> to ensure compile-time type safety

  • Created a PipelineBuilder<TViewCtx> builder pattern class to separate construction of pipelines and composition of steps for locality of behavior. Builder class uses Add_ShortCircuit(), Add_Middleware(), and InjectMainMethod() public methods to compose pipelines modularly.

  • NUnit and Unity TestRunner Test Suite

  • Build a comprehensive NUnit + Unity TestRunner framework suite validating pipeline composition, short-circuit flow, execution, async/timed behavior integration with custom Timers system,

  • Ensured step composition ordering correctness and context devivery

  • Resolver system integration

  • Integrated a custom Resolver system to abstract execution of pipeline actions (callbacks, waits, timers) decoupling step definition from runtime behvaiour & separated out execution responsibility to PipelineExecutor<TViewCtx> to manage Resolver integration

  • Designed pipeline steps to resolve through a unified IResolvable interface, allowing synchronous, asynchronous and time-based operations to be composed uniformly within the same execution paradigm

KEY DESIGN ANALYSIS & WHAT I LEARNED

KEY DEsign analysis

why pipeline?

  • Decomposes complex execution into sequential, and isolated stages, improving readability, testability, and maintainability over complex logic webs

  • Enables composible, modular, and extensible behaviour, where steps can be added, removed and or re-ordered without rewriting system flow

why resolver abstraction?

  • Decouples what a step does from how it executes, allowing callbacks, async waits, and timed operation handling through a unified exaction abstraction

  • Creates a extensible plug-and-play abstraction layer that allows for new behaviours (timers, async, gates) to integrate with pipeline execution without modifying pipeline logic, improving scalability & system longevity

Why immutable context delivery?

  • Guarantees read-only safety across system boundries & creates a snapshot of system state avoiding race condition problems.

Why short-circuit model?

  • The original reason for this system, serving as an advanced way of guard-clausing, providing early exit control flow preventing unnecessary work and allowing failure or gating conditions to stop execution

  • Creates conditional orchestration, where steps can branch behavior (before/after/fail) while enforcing strict execution guarantees and not bloating code with complex nested logic.

What i learned

Context Immutability Design

  • There are different levels to immutability in different programming layers to make data immutable.

  • I chose interface-level immutability to prevent reference mutation while maintaining ergonomic usage.

  • This means making the context be immutable at the class level, so it looks like this:

  • The neat thing about this is that the implementation of the ContextView interface is integrated within the { get; private set; } definition of the concrete class. Meaning there are no extra semantic indirection.

Performance Considerations for Data Throughput

  • Another important peice of information I gleaned is that high-throughput is important for systems that constantly send data around.

  • Meaning using value-types even if the data is small, is not a good design decision based on the rate at which data is sent.

  • The pipeline system is designed for the Unity Player Loop, meaning it can hook into Update, FixedUpdate, etc.

  • Therefore the execution can be called every frame. This would be a problem with a value-type system.

  • However using reference-types the issue of rapid copies creating many one-shot copies is avoided.


INTERESTED IN MY WORK?

LETS DISCUSS!

Documentation in Progress :)

INTERESTED IN MY WORK?

LETS DISCUSS!