Building Applications with Scala - podcast episode cover

Building Applications with Scala

Jun 07, 202622 min
--:--
--:--
Download Metacast podcast app
Listen to this episode in Metacast mobile app
Don't just listen to podcasts. Learn from them with transcripts, summaries, and chapters for every episode. Skim, search, and bookmark insights. Learn more

Episode description

A comprehensive technical guide designed to transition developers into experts in functional and reactive programming. The book provides a structured roadmap, beginning with Scala language fundamentals and core concepts like immutability and monads before moving into advanced architectural patterns. Readers explore the broader Scala ecosystem by learning to use the Play Framework for web interfaces, Akka for distributed actor-based systems, and Slick for database persistence. Beyond syntax, the text emphasizes practical skills such as behavior-driven development, REST API design, and performance tuning. The final chapters provide a strategic overview of system scalability, covering modern deployment tools like Docker, AWS, and the NetflixOSS stack. Ultimately, this resource serves as a bridge between academic functional theories and the practical demands of building modern, resilient software.

You can listen and download our episodes for free on more than 10 different platforms:
https://linktr.ee/cyber_security_summary

Get the Book now from Amazon:
https://www.amazon.com/Building-applications-Scala-Diego-Pacheco/dp/178646148X?&linkCode=ll2&tag=cvthunderx-20&linkId=a84c1f12f06bf474d1b8263e4526504d&language=en_US&ref_=as_li_ss_tl

Discover our free courses in tech and cybersecurity, Start learning today:
https://linktr.ee/cybercode_academy

Transcript

Speaker 1

You know, usually when we think about building a massive digital platform, something that handles millions of requests a second, we picture this incredibly complex, chaotic web of moving parts. Oh absolutely, Like I always imagine a giant, sprawling restaurant kitchen. You have thousands of cooks constantly shouting tweaking recipes on the fly, grabbing ingredients out of each other's hands, you know, just to keep the whole dinner service from collapsing, right, And.

Speaker 2

That kitchen analogy highlights the exact danger developers face at scale, which is race conditions. Yeah, because when two chefs reach for the salt a millisecond apart and try to use it simultaneously, I mean, the entire system just crashes. It really feels like the bigger the architecture gets, the more inherently fragile it should be.

Speaker 1

But then you look under the hood of the apps you probably use just this morning. I mean, if you scroll through Twitter, ordered Nuber, watch Netflix, or bought something on Amazon recently, you haven't been interacting with a chaotic, fragile kitchen.

Speaker 2

No, not at all.

Speaker 1

You've been interacting with systems scaled using these remarkably stable, rigidly disciplined principles running on the Java virtual machine.

Speaker 2

And that stability. It actually came out of a painful industry wide realization because for decades the software world relied heavily on object oriented programming.

Speaker 1

Like Java or C sharp, Python exactly.

Speaker 2

Those languages established the bedrock of enterprise software. But as our digital world just exploded in scale, we hit this massive wall with concurrency.

Speaker 1

Meaning handling tons of users.

Speaker 2

At once right, handling millions of simultaneous users in traditional OOP, it required a nightmare of threadlocking and synchronization. We desperately needed a different approach.

Speaker 1

Which is the core mission of our deep dives. Today we are exploring the world of functional programming and a language called Scala, using our source material on how to build applications with it. Yeah, we're going to unpack exactly how the biggest tech companies keep the Internet running without their servers, you know, constantly catching on fire.

Speaker 2

It's a fascinating shift.

Speaker 1

So Scala enters the picture in two thousand and one, created by Martin O. Durski, and the text describes it as this post functional multi paradigm language.

Speaker 2

Yeah, it bridges a massive gap, but to understand how it solves modern concurrency problems. We actually have to look backward. Okay, functional programming's roots. They go all the way back to mathematical abstractions from the nineteen thirties, specifically this formal system called lambda calculus.

Speaker 1

Wait the nineteen thirties.

Speaker 2

Yeah, the nineteen thirties, And the very first language implementation of these ideas was Lisp back in the nineteen fifties.

Speaker 1

That's wild. I mean, I always assume functional programming was this modern, cutting edge Silicon Valley trend. But you're telling me it's practically ancient history and computer science.

Speaker 2

It is. But back in the nineteen fifties, maintaining the pure immutable state required by functional programming was incredibly expensive computationally.

Speaker 1

Like, the machines just couldn't handle it right.

Speaker 2

Computers just didn't have the memory or the processing power to do it efficiently. But today, well, hardware has finally caught up to the math. I see, those math based principles from the fifties are now what power the most modern infrastructure. We have massive big data tools like Hadoop or Spark. They're built entirely around map.

Speaker 1

Reduce, which is a functional concept.

Speaker 2

Literally, a functional programming concept. We've taken pure academic math and applied it to modern web scale traffic.

Speaker 1

Okay, so we have this beautiful nineteen thirties mathematical purity. But purity doesn't survive in the methi reality of modern web traffic unless it has an absolute workhourse of an engine to run on. That's right, and that's the compromise skull I had to make. It runs on the JVM. So it's like taking the aerodynamic ultra light chassis of a Formula one car and bolting it directly onto the undercarriage of a massive diesel freight train.

Speaker 2

I love that analogy.

Speaker 1

You get the cutting edge design, but you also get the unstoppable, heavy duty momentum of the track.

Speaker 2

Yeah, and that is the engineering pragmatism that made Skala a huge success. Tethering's Gala to the JVM provides massive immediate leverage. Also, you get native access to the entire existing Java ecosystem, all those frameworks, enterprise library, security tools that developers have spent the last twenty years building. Yeah, Scala can interact with them natively.

Speaker 1

I still have to push back a little here, though. Sure if functional programming is this massive evolution from object oriented programming. Why not just build a totally new runtime environment from scratch. Why tether this sleek f one car to legacy infrastructure.

Speaker 2

It really just comes down to operational leverage. The JVM is entirely battle tested by web scale companies. It has proven it won't break when a million people click a button at the exact same time, and more importantly, your IT and DevOps teams they already know how to deploy, monitor, and scale JVM applications.

Speaker 1

Ah, so there's no learning curve for the operation side.

Speaker 2

Exactly, if you introduce a completely new language with a completely new run time, you force a company to been millions of dollars rebuilding their entire deployment pipeline.

Speaker 1

That makes a lot of sense.

Speaker 2

With Scala, a company's operations team can run the application exactly the same way they run legacy Java apps. Plus Scala code can call Java code and vice versa.

Speaker 1

So you aren't forcing an enterprise to just throw away twenty years of legacy code just to modernize their concurrent processing.

Speaker 2

Right.

Speaker 1

Okay, that makes perfect sense. But since Scala runs on the exact same engine as Java, the difference isn't the machine itself. The transition we're talking about today is entirely about the mindset of the developer driving it, and it.

Speaker 2

Requires a radical shift. You're moving from imperative programming to declarative programming.

Speaker 1

I get the declarative mindset in theory, you know, telling the system what I want to accomplish, not how to do it. Yes, But mechanically, if I take away a developer's ability to use imperative tools like for loops and STANDARDI fel statements that mutate variables, aren't I just crippling their toolkit? How does Scala compensate for them?

Speaker 2

Well, you aren't crippling the toolkit. You're elevating the abstraction.

Speaker 1

Elevating the extraction.

Speaker 2

Yeah.

Speaker 1

Right.

Speaker 2

Imperative programming involves micromanaging the computer's state. You use statements to manually dictate the sequence of operations. Update this counter, move this pointer, check this condition, very step by step exactly declarative programming, specifically, in a functional paradigm, it focuses on composing expressions. Okay, Instead of a for loop that mutates a counter variable, you use recursive structures and higher

order functions like map, filter or reduce. Those functions transform a collection of data into a new collection without ever altering the original.

Speaker 1

And a big part of that shift is tackling what the architecture documentation calls the ultimate villain in software design, shared mutable state.

Speaker 2

Oh yeah, shared mutable state is basically the root cause of almost every major concurrency bug in existence.

Speaker 1

Wow.

Speaker 2

It's essentially a global variable that multiple different functions or threads have direct access to, and they can modify it at any given moment.

Speaker 1

Returning to our restaurant kitchen, shared mutable state is having ten different chefs standing around a single pot of soup. Yes, exactly, One chef adds salt, another unexpectedly swaps out the chicken broth for beef broth. Another turns the heat up to boiling, and none of them are communicating, which is a disaster, total chaos. When the soup finally reaches the customer, it's ruined and you have absolutely no idea which chef destroyed it or at what specific millisecond the error occurred.

Speaker 2

And that lack of traceability is the true nightmare of shared mutable state. It makes systems incredibly difficult to scale. I can imagine refactoring the codebase becomes terrifying because you can never trust the local method. You have to trace every single function across the entire program that might touch that global variable. Just to understand the logic.

Speaker 1

That sounds exhausting, it is.

Speaker 2

Functional programming avoids this entirely by ensuring state is kept local and isolated.

Speaker 1

So in the ft kitchen, every chef gets their own ingredients, their own private cutting board, and a strict recipe that absolutely cannot be altered mid cook. Precisely which brings us to the actual rules of this new kitchen. The core pillars of functional programming. The biggest one, the absolute bedrock of this philosophy is immutability.

Speaker 2

Yeah, and immutability simply means that once a value is assigned to a variable, it can never ever be changed. It is locked in memory.

Speaker 1

But wait, if I can never change you variable, how does my application actually process data? Like if a user updates their profile picture and their profile object is immutable, how do they get a new picture?

Speaker 2

So you replace state mutation with discipline state discipline state right. Instead of overwriting the existing profile object with the new picture, your function creates a brand new instance of the profile object that contains the new picture while preserving the old one. You leave the original data completely alone.

Speaker 1

But wouldn't that use a massive amount of memory just constantly creating copies of everything.

Speaker 2

It would if it were literally copying everything, But Scala uses highly optimized structural sharing under the hood. Oh, when you create that new profile object, it actually shares references to all the unchanged data like the username and email from the original object.

Speaker 1

That's clever.

Speaker 2

Yeah, it only allocates new memory for the piece that changed, and the operational payoff for this is massive because there are no side effects. Your code is parallel by nature.

Speaker 1

Because multiple threads can read that data at the exact same time without locking each other out.

Speaker 2

Yes, you completely eliminate the need for thread synchronization locks. Your program can run incredibly fast concurrently across dozens of processors.

Speaker 1

Because no function is ever waiting to see if another function is currently mutating the data exactly. It mathematically eliminates the traffic jams in the system.

Speaker 2

It really does.

Speaker 1

So that brings us to how we actually manipulate this immutable data. The functions themselves. In functional programming, they get special treatment. We hear the terms first class function and higher order functions thrown around constantly.

Speaker 2

Yeah, and treating functions as first class citizens. Means the programming language treats a function exactly the same way it treats an integer or a string. Okay, you can assign a function to a variable. You can pass a function as an argument into another function. You can even return a function as the result of an operation.

Speaker 1

So they aren't just rigid script sitting on a server. They're fluid pieces of data you can pass around your architecture.

Speaker 2

Right, and that leads to higher order functions. These are functions that take other functions as parameters.

Speaker 1

Got it.

Speaker 2

This enables incredibly powerful techniques like currying and partial functions.

Speaker 1

Okay, currying, let's unpack that.

Speaker 2

Currying is a mathematical technique where you take a function that requires multiple parameters and you transform it into a sequence of chain functions where each function takes only a single argument.

Speaker 1

Okay, I need a concrete example of that. Why would I want to break a perfectly good multi parameter function into a chain of single argument functions.

Speaker 2

Well, imagine you have a function that queries a secure database. It requires three arguments, an authentication token, the database endpoint, and the actual query payload.

Speaker 1

Siple enough.

Speaker 2

Instead of passing all three arguments, every single. Time a UI component requests data, currying allows you to basically bake in the authentication token. Once that applications start up, you pass the token in and it returns a new function that only requires the endpoint and payload. Then you can bake in the end point, returning yet another new function that only needs the payload.

Speaker 1

Oh wow, So I can pass that final single argument function down to my front end UI components exactly, and the UI just passes the query payload totally unaware of the complex authentication or endpoint routing happening behind the scenes. You're building customized single purpose tools on the fly.

Speaker 2

It creates incredible modularity. It's heavily utilized in pure functional languages like Haskell and Skoalar provides native support to build these pipelines effortlessly.

Speaker 1

This is where the architecture really starts to click for me. But here's the piece of the puzzle that initially threw me off.

Speaker 2

What's up.

Speaker 1

Scalar relies on a statically type system, A strong type system. My instinct says that rigid, strict typing means more boilerplate, more rules, and inevitably more testing to make sure everything aligns. A lot of people think that, yet the documentation makes this wild claim. A strong type system actually forces you to write fewer.

Speaker 2

Tests, and it does because Skala is statically typed. You're shifting the burden of validation from run time tests back to compile time. Okay, the compiler essentially becomes your strictest editor in your first line of defense. Oh so well, in a dynamically typed language like JavaScript or Python, you might write a function that expects a user's age as an integer and a separate service accidentally passes the word

thirty as a string. Right, the program will accept it, and it might not crash until it's actually running live in production and tries to run math on a word.

Speaker 1

Which is exactly why to developers in dynamic languages spend hours writing massive suites of unit tests just to verify. You know, is this number? Is this a string? Please handle this gracefully, right.

Speaker 2

But in a strong type language like Scala, you define the exact type upfront in.

Speaker 1

The function signature, so it's locked in.

Speaker 2

If that function demands an integer type and you try to pass it a string of texts, the compiler simply refuses to build the application. It won't let you make that basic routing mistake, you don't have to write a test checking if the input is an integer, because it is mathematically impossible for the wrong data type to enter that function in the first place. The compiler catches the error before the program ever executes.

Speaker 1

And that leads directly into another core concept you see constantly in functional architecture, referential transparency.

Speaker 2

Yes, referential transparency is the ultimate result of combining immutability with strict types. Okay, it means that any function call can be seamlessly replaced by its output value without changing the behavior of the program.

Speaker 1

Break that down mechanically. Why does that matter computationally?

Speaker 2

Think of it like a math equation. If x equals five, and why equals x plus two, you can confidently just replace x with five. Everywhere you know the answer is always seven. But in imperative programming, a background thread might have mutated x to equal ten right before why was calculated? You can't trust the variable unpredictable exactly because Scala enforces immutability. A function called calculate tax given the input one hundred, will always unequivocally return ten.

Speaker 1

Because nothing else can mess with it.

Speaker 2

Right, Because it relies on no external mutable state. The system can safely cache that result ten across one thousand different servers.

Speaker 1

So you don't have to waste CPU cycles constantly recalculating it or checking if the global tax rate variable changed in the background. That cuts out massive amounts of compute time at scale.

Speaker 2

Yeah, the code essentially becomes its own reliable mathematical documentation. You can parallelize and cache aggressively, which is the secret to scaling applications to millions of users.

Speaker 1

Okay, so we've established the philosophy. We have our disciplined immutable kitchen where chefs pass around first class functions and the compiler acts like a straight head chef, checking every ingredient at the door.

Speaker 2

That's a great summary, but.

Speaker 1

Let's look at the actual reality the code. Comparing Java to Scala side by side.

Speaker 2

The best place to start that comparison is in the interactive shell, the r epl.

Speaker 1

Right, the read evil, print and loop. Because if I want to write a standard Java application to test a quick piece of logic, I have to configure a whole project environment.

Speaker 2

It's a hassle.

Speaker 1

But with Scala, you just open your terminal type Scala and you drop straight into an interactive loop. You type of command, it evaluates, it prints the result, and waits for the next input.

Speaker 2

It creates an incredibly fast feedback loop for developers. You can test complex functional pipelines without compiling an entire enterprise application.

Speaker 1

In slight way.

Speaker 2

Yeah, but when we look at formal application structure, the verbosity of Java compared to the conciseness of Scala is stark.

Speaker 1

It really is. The documentation gives a great side by side Hello World showdown. In Java, printing a simple phrase to the screen requires about six lines of code. You have to define your package to find a public class, write out the incredibly formal method, signature of public static void, mainstream, brackets, arcs, and finally call system dot out dot print.

Speaker 2

In it's an immense amount of ceremony for a simple action.

Speaker 1

Right, and in Scala, achieving the exact same result takes three lines. You write object hello world, extends app, open your bracket, write print on Hello World, and close it.

Speaker 2

Yeah. By extending that app trait, Scala completely abstracts away the need for the developer to define that massive main method. It's built into the language.

Speaker 1

It's so clean, but there's a specific keyword you just used. That signifies a massive architectural difference. You said object, Hello world, not class Hello World.

Speaker 2

Ah. Yes, this is a crucial distinction in maintaining a discipline state. In Scala. Simply using the key word object instead of class automatically creates a singleton pattern at the language level.

Speaker 1

And just to clarify the mechanics for a second, a singleton is a design pattern used when you only ever want one single instance of an object to exist across the entire system, exactly, things like database connection pools or configuration managers. But doing this safely in Java is notoriously difficult.

Speaker 2

Oh, building a thread safe singleton in Java requires a nightmare of boilerplate.

Speaker 1

Really.

Speaker 2

Oh yeah, You have to write a private constructor so other classes can't instantiate it. You need a static instance variable, You have to write a get instance method. And that's just the start, right, Because if you are in a multi threaded environment, you have to implement double checked locking with synchronization blocks just to ensure two threads don't accidentally create two instances at the exact same millisecond. Wow, it takes over a dozen lines of complex, error prone code.

Speaker 1

And in Scarlight you just type the word object. That's it.

Speaker 2

The language provides the thread safe abstraction implicitly. It handles the lazy initialization safely under the hood.

Speaker 1

That's amazing.

Speaker 2

When you multiply that reduction in boiler played across a million line code base, the cognitive load on the developers drops dramatically. Writing less code mathematically means you have a smaller surface area for bugs to hide.

Speaker 1

Let's close out the code segment with the absolute basics of how variables are handled. Because we said immutability is the core of functional programming, but we also know Scala is multi paradigm. Does the language physically force you to only use immutable variables.

Speaker 2

It doesn't force you, but it's design deeply favors it. You have two options for declaring variables in scalavarn val. If you use var, you are creating a mutable reference of value you can overwrite later.

Speaker 1

The dreaded mutable state.

Speaker 2

Well, it's only dreaded if you allow it to escape your local scope.

Speaker 1

Fair point.

Speaker 2

Sometimes mutating a local counter inside a highly isolated function is just more computationally efficient. But the standard default in Scala is val, and val means when you dec fila of variable. With val, you are creating a strictly immutable reference. Once it points to an object, it can never be reassigned.

Speaker 1

Never.

Speaker 2

The compiler will literally throw an error and halt the build if you attempt to reassign it.

Speaker 1

So it's building the guardrails directly into the syntax exactly. So, looking at this entire journey from nineteen thirty's math to compiling immutable variables on the JVM, what does this all mean for you, the listener?

Speaker 2

It's a big question.

Speaker 1

This deep dive wasn't just about learning a new programming syntax or comparing the spelling of Java versus Skala. What we're really talking about is a profound philosophy of predictability.

Speaker 2

Yeah, when you eliminate shared mutable state, lock down your values with immutability, and let a strict compiler catch your logical errors before runtime, you remove the chaos from the system.

Speaker 1

You totally do.

Speaker 2

You shift from hoping your application works to mathematically proving it works.

Speaker 1

And that predictability is exactly what provides the unbelievable horsepower required to the world's biggest digital platform smoothly, absolutely, but beyond the server room, the core concepts of functional programming actually offer an incredibly interesting lens for how we process information in our own lives.

Speaker 2

It really is a fascinating parallel think about how we operate as human beings in the modern world. Okay, we have dozens of browser tabs open, our phones are constantly buzzing. We're trying to retain a thought for an upcoming meeting while actively listening to a conversation.

Speaker 1

Guilty is charged.

Speaker 2

We are constantly allowing external side effects to interrupt our local functions. We essentially live our lives as one giant, chaotic, shared mutable state.

Speaker 1

We are constantly getting our internal variables overwritten by distractions.

Speaker 2

Which leaves us with a compelling final thought, love that if enforcing strict constraints like absolute immutability and zero side effects is the exact mechanism that allows our computing systems to become infinitely more scalable, resilient, and creative, how might

we apply that to our own own daily workflows. If we treated our current task as a pure function, blocking out all external inputs, refusing to let our attention be mutated by an incoming notification, could adopting a functional mindset actually free us from our own mental bugs and cognitive overload.

Speaker 1

Shutting down the chaotic kitchen in our own minds. Every chef gets their own cutting board exactly. It is definitely something to experiment with the next time you sit down to focus. Thank you so much for joining us on this deep dive today. We hope it gave you a totally new perspective on the invisible architecture running the modern world. Keep exploring, keep questioning the systems running behind the scenes, and we will catch you next time.

Transcript source: Provided by creator in RSS feed: download file
For the best experience, listen in Metacast app for iOS or Android