Senior Software Engineer & Data Engineer | Scala & Rust | Functional Programming
I am a Senior Software Engineer and Data Engineer specializing in the design and implementation of highly concurrent, distributed, and data-intensive systems. My methodology is deeply rooted in the rigorous application of Functional Programming principles, operating at the intersection of applied category theory, robust data engineering, and high-performance systems programming in Scala and Rust.
I engineer software architectures where types carry precise semantic meaning, effects are explicitly modeled, and algebraic composition is the primary scaling mechanism.
If an invariant is not encoded in the type system, it is merely a convention.
I provide specialized freelance engineering and technical consulting for organizations aiming to construct resilient, scalable architectures or modernize their existing infrastructure. My core competencies include:
- Distributed Systems & Data Engineering: Architecture and implementation of robust data pipelines and streaming platforms (Apache Spark, Apache Kafka).
- High-Performance Microservices: Building scalable backend services utilizing advanced Scala (ZIO, Cats) and systems programming in Rust.
- Architectural Modernization: Transitioning legacy codebases into strictly typed, functionally pure architectures to drastically reduce technical debt and runtime anomalies.
- Technical Mentorship: Elevating engineering teams through the adoption of functional programming disciplines and type-driven design.
Connect with me: Personal Website | Curriculum Vitae | LinkedIn | Technical Blog
I do not view Functional Programming merely as a stylistic choice or a suite of tools, but rather as a formal discipline for reasoning about software correctness. My objective is to engineer systems that remain understandable, provably correct, and adaptable under extreme technical constraints.
Types are not documentation; they are formal, executable constraints. If an invariant is critical to the domain, it belongs in the type system. A function that admits more states than it can safely process is fundamentally dishonest.
Effects are not incidental occurrences—they are explicit descriptions of program behavior. An effectful program is a value; its interpretation is a distinct and separate concern. Concealed side effects are the most insidious form of technical debt.
An abstraction lacking algebraic laws is merely a fragile interface. Laws provide the formal guarantees required for fearless refactoring and predictable composition. If an abstraction cannot be reasoned about algebraically, it is analytically deficient.
Complex systems are not engineered by arbitrarily appending features, but by composing smaller, well-behaved, and verifiable components. True composition requires explicit dependencies, strictly controlled effects, and deterministic data flow.
Every runtime validation is a belated mitigation of a flawed domain model. The earlier an invalid state is mathematically rejected by the compiler, the safer the system. The optimal error is the one that cannot be syntactically expressed.
Mathematical abstractions and zero-cost architectures are desirable; accidental complexity is not. High performance and rigorous Functional Programming are not mutually exclusive—they are intrinsically aligned when system boundaries are appropriately drawn.
The following examples demonstrate how these principles translate into tangible software architecture: domain algebras expressed as formal traits or typeclasses, explicitly modeled effects, and strict interpreter-free composition.
This Scala snippet exemplifies type-driven design: enforcing invariants without inheritance hierarchies or hidden side effects, utilizing purely algebraic definitions.
import cats.{ Functor, Order }
import cats.syntax.functor.*
// Domain — opaque type enforces semantic boundary at zero runtime cost
opaque type Date = Long
object Date:
def apply(value: Long): Date = value
given Order[Date] = Order.by(identity)
final case class Timeline[+A](at: Date, value: A)
// Algebra — higher-kinded interface; F[_] is the effect abstraction
trait PersonAlg[F[_]]:
def about: F[Info]
def experience: F[List[Timeline[Experience]]]
def education: F[List[Timeline[Education]]]
def skills: F[Stack]
// Program — algebra over F[_], independent of any concrete interpreter
trait CurriculumVitae[F[_]]:
def about: F[Info]
def experience(at: Date): F[List[Experience]]
def education(at: Date): F[List[Education]]
def skills: F[Stack]
// Smart constructor — requires only Functor; no effect system dependency
object CurriculumVitae:
def apply[F[_]: Functor](alg: PersonAlg[F]): CurriculumVitae[F] =
new CurriculumVitae[F]:
def about = alg.about
def skills = alg.skills
def experience(at: Date) = alg.experience.map(_.flatMap(collectUntil(at)))
def education(at: Date) = alg.education.map(_.flatMap(collectUntil(at)))
private def collectUntil[A](at: Date)(using Order[Date]): Timeline[A] => List[A] =
case Timeline(date, value) if Order[Date].lteqv(date, at) => List(value)
case _ => NilThis Rust implementation mirrors the same architectural rigor: traits as behavioral algebras, explicit effect handling via Result, and mathematical correctness enforced by the borrow checker and type system.
View Rust implementation
// Domain
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Date(u64);
#[derive(Clone)]
pub struct Timeline<A> {
pub at: Date,
pub value: A,
}
// Algebra
pub trait PersonAlg {
type Error;
fn about(&self) -> Result<Info, Self::Error>;
fn experience(&self) -> Result<Vec<Timeline<Experience>>, Self::Error>;
fn education(&self) -> Result<Vec<Timeline<Education>>, Self::Error>;
fn skills(&self) -> Result<Stack, Self::Error>;
}
// Program Definition
pub struct CurriculumVitae<P> {
person: P,
}
impl<P: PersonAlg> CurriculumVitae<P> {
pub fn new(person: P) -> Self {
Self { person }
}
pub fn about(&self) -> Result<Info, P::Error> {
self.person.about()
}
pub fn skills(&self) -> Result<Stack, P::Error> {
self.person.skills()
}
pub fn experience(&self, at: Date) -> Result<Vec<Experience>, P::Error> {
self.person.experience().map(|xs| Self::collect_until(at, xs))
}
pub fn education(&self, at: Date) -> Result<Vec<Education>, P::Error> {
self.person.education().map(|xs| Self::collect_until(at, xs))
}
fn collect_until<A>(at: Date, xs: Vec<Timeline<A>>) -> Vec<A> {
xs.into_iter()
.filter(|t| t.at <= at)
.map(|t| t.value)
.collect()
}
}





