Learning Scala: Why Functional Programming Matters for the Systems We Build Today
In 1983 I asked my parents for an Atari for Christmas. Instead, I got a Commodore 64. I was disappointed at first, until I discovered how much cooler Wizard of Wor was than Combat. To their credit, my parents thought a computer was a better investment than a video game. I used that C64 through my sophomore year of college, until I replaced it with a 486, my first real investment. Like many in my generation, I cut my teeth on languages like BASIC and LOGO without really picking them for any reason. It was just cool, as a kid, to tell a computer what to do and watch it do it. I quickly understood that animating ASCII stick figures was a BASIC problem, while digital Spirograph was a job for the LOGO turtle. In college, I used FORTran for math and science and C for everything else, knowing that, depending on the task, one language was more natural than the other.
TL;DR
Functional programming isn't an academic exercise. It directly targets the problems that make systems hard to run at scale: unpredictable state, hidden side effects, concurrency bugs, and distributed inconsistency. Immutability turns shared state from a liability into a fact you can reason about. Pure functions make behavior testable and honest. This post kicks off a series applying these ideas to Scala, working through real commerce systems one concept at a time.
How I Got Here
It wasn't until many years later, while taking a survey class in programming languages, that I seriously thought about why languages were different and why I should care. I disregarded Pascal, our token procedural language, as just a more rigorous version of BASIC or C for people who like to type. I didn't love Smalltalk, but it improved my C++ by teaching me to think object-oriented. Prolog was an eye-opener. It was fun, but outside of being useful for proofs of formal logic, I filed it away as an option in case I was ever unfortunate enough to need it in real life. Scheme blew my mind. Other than making it easier to read and write cLISP (I'm a retired emacs weenie), I never used it professionally, but this functional language changed the way I programmed in every language I've used since, to my benefit. Thought and language truly impact each other immensely, and limiting yourself to a single language severely limits the boundaries of your comprehension and creativity. I believe that's as true for natural languages as it is for computer languages, and it extends to the arts and any other form of expression. But that's philosophy.
So I learned Java like everyone else, and I've used it primarily for the last 30 years.
There are plenty of reasons for Java's wide adoption, and that's the subject of many discussions, new and old, that I have no interest in reviewing. Without diminishing its value, or the brilliance of its creators and most talented users, it always felt like a compromise to me. I've written many things in it, but I never really expressed myself in Java, or felt it helped me do something I couldn't do better in another language.
The Conversation That Changed My Mind About Beginning Scala
I can't remember the first time I heard of Scala, but I recall it being brought to my attention as an alternative to Java. Naturally, knowing a few other languages, and given my investments and goals at the time, I dismissed it. Why bother learning a new thing to do the same old stuff a new way? Between then and 2020 it rarely came up, except in certain circles where, career-wise, I was on the fringes. I looked a bit more closely at one point, decided it had some genuinely interesting features, and, finding it difficult for me to read and seeing no career-driven reason to take it any further, left it there. Frankly, with the LLM buzz in full swing at the time, my budget for self-exploration was already spent elsewhere.
A friend and colleague who'd jumped on the Scala wagon changed my perspective. He got me looking at Scala as a vehicle for functional programming, and at functional programming as an often-overlooked way of addressing many of the issues we still struggle against across the modern SDLC. This landed while my mind was already occupied with bridging the gaps between natural and computer languages in processes built on LLMs. It wasn't so much a single conversation as a recurring set of themes that evolved and blurred over whiskey and cigar smoke at our weekly meet-ups. Here goes nothing…
Why Functional Programming Matters for Today’s Software Problems
The thing that struck me hardest when I finally revisited functional programming, years after Scheme had first rewired my thinking, was how directly it speaks to the kinds of problems we spend most of our careers fighting:
unpredictable state
hidden side effects
concurrency bugs
accidental complexity
data races
distributed inconsistency
systems that drift into chaos the moment they succeed at scale
None of these are “Java problems” or “Python problems” or “legacy problems.” They are the natural consequence of an industry that still treats mutability and side effects as the default. However, FP treats those same things as hazards to be isolated, minimized, or reasoned about explicitly.
Immutability Isn’t Academic, It’s Defensive Architecture
If you've ever spent days trying to reproduce a race condition that only shows up in production, under load, across multiple nodes, you already know why immutability matters. Immutable values behave like facts, even in distributed systems, where shared mutable state is the slowest-moving catastrophe in the stack. Most of the bugs we call "hard" are really just "mutable."
Pure Functions Are the Beginning of Reliability
Pure functions aren’t about elegance. They’re about accountability. A pure function is honest because it has no hidden agenda:
no reaching into global state
no tapping a logging side effect
no mutating something you’ll regret
no concurrency traps
no need for a mocking circus just to test it
When you scale a system built from pure functions, you aren’t scaling the surface area for nondeterminism. You’re scaling predictability.
Expressions Instead of Instructions
When your code shifts from "do this, then this, then maybe this" to "this expression is the logic," an entire class of defects disappears. Not because you solved them, but because that style of thinking makes those defects unrepresentable. It's why FP crept quietly into domains that demand rigor: finance, concurrency-heavy platforms, distributed data systems, regulated products. I just didn't see it at the time, too focused on the details of individual issues to notice the root cause that unified them.
Functional programming gives you constraints that happen to align with correctness.
Why Start Scala, Not Just Any Functional Language in 2026
I mentioned I'll be picking up Kotlin and Rust alongside Scala this year, and I want to be direct about why Scala carries this series. Kotlin and Rust are both worth a developer's time, and both borrow functional ideas. Neither was built with functional programming as a first-class citizen the way Scala was.
Scala runs on the JVM, which means it drops into the same ecosystems, build tools, and production environments most backend teams already run. But it treats immutability, pure functions, and pattern matching as defaults rather than opt-in features bolted onto an object-oriented core. That combination, JVM-native and functional-first, is rare. It's why this series lives in Scala even as I poke at other languages on the side.
Brave New World?
So why write this now? Scala isn't new, nor is the SDLC, and FP certainly predates me. I'm not an expert in any of this, and I haven't made any new or insightful contributions to these domains. I just know that any noteworthy insight I've had in my life came from reexamining something I thought I already understood, in the context of a new intersection of issues or domains.
Modern SDLC pressures are converging:
LLMs making code easier to write, but not easier to reason about
Systems becoming more concurrent, more distributed, more event-driven
Organizations needing architectures that reduce risk, rather than heroically react to it
Functional programming, practiced pragmatically and not religiously, offers tools we desperately need to confront this complexity without becoming its custodians.
It's not about programming in a new style. It's about thinking in a new style, and thinking scales better than tooling.
So I decided to dedicate the bulk of my Sundays in 2026 to working through these themes in a blog, instead of church, football, and other things I loathe. I intend to explore functional programming while learning a bit more about Scala, Kotlin, and Rust through the lens of my experience with the software development life cycle and the ongoing impact of LLMs and other aspects of practical machine learning on the SDLC.
What's Coming in My Learning Scala Series
I'm dedicating the bulk of my Sundays in 2026 to working through these ideas in Scala, one real problem at a time. Each post takes a functional programming concept and applies it to a system you'd actually build: order state, money, concurrency, traceability.
A few places to go next once you've read this one:
Pattern Matching, on replacing conditional sprawl with exhaustive, compiler-checked logic
Immutability and Reliable Systems, which goes deeper on the defensive-architecture idea above
Pure Functions and Concurrency, on what pure functions buy you once threads enter the picture
Frequently Asked Questions
What is functional programming and why does it matter?
Functional programming is a style built around pure functions and immutable data instead of mutable state and side effects. It matters because it directly targets the causes of hard-to-reproduce bugs in production systems: unpredictable state, hidden side effects, and concurrency races.
Why does immutability help prevent bugs in distributed systems?
Immutable values can't change after creation, so they behave like facts even when shared across multiple nodes. Most bugs described as hard to reproduce trace back to mutable shared state, not genuine logical complexity.
What makes a function pure in programming?
A pure function always returns the same output for the same input and has no side effects. It doesn't reach into global state, mutate external data, or depend on anything outside its own arguments, which makes it predictable and easy to test.
Why is Scala a strong language for learning functional programming?
Scala runs on the JVM, so it fits into ecosystems most backend teams already use, while treating immutability, pure functions, and pattern matching as language defaults rather than bolted-on features. That combination of JVM compatibility and functional-first design is uncommon.
How does functional programming help with concurrency?
Because pure functions don't touch shared mutable state, they remove an entire category of concurrency bugs before they can occur. Code built from pure functions scales in predictability rather than in surface area for nondeterminism.
What will this Learning Scala series cover?
The series applies functional programming concepts to real systems built in Scala, including pattern matching, immutability, pure functions and concurrency, and modeling business logic, using concrete examples drawn from commerce systems.