
Set up your environment for the Scala advanced course, download the exercises and support materials, and get ready to follow along, try the examples, and complete the exercises.
Prepare your Scala Part 2 workspace by installing a JDK (8+), using Oracle JDK for compatibility, and setting up SBT plus IntelliJ IDEA Community Edition, then import and unpack exercises.
Verify you have Java 8 or 9 installed as a JDK by running javac -version; if missing, download Java SE from Oracle and use the Linux PPA on Ubuntu.
Install skarner, download intelligence or download sbt, and the standalone scanner; on macOS unzip it and add the bin directory to your path, then verify by launching from the terminal.
Install sbt across Linux, Mac, or Windows from the official pages; use the terminal to run sbt and sbt version to verify a recent 1.x release with automatic downloads.
Install the IntelliJ IDEA community edition, enable the Scala plugin during the wizard, and skip the VI plugin unless you know what you're doing.
Configure IntelliJ by setting the Project SDK in project defaults and structure, adding a new JDK on Mac if needed. Then import the Scala course zip with slides and exercises.
Unpack the advanced exercises, set up the SBT project, and import it into the IDE to run module tests, fix failing tests, and use runnable worksheets to experiment.
Explore modularity in Scala and implement dependency injection to improve compile times, development freedom, and testability by injecting and reconfiguring dependencies at scale.
Explore static cling and hard wired dependencies, compare classes and objects in Scala, and learn compile time dependency injection with parfait and cake patterns, plus constructor and runtime strategies.
Explore how static cling creates inflexible resource dependencies in Scala via the singleton pattern, and see how hard-wired database details hinder testing and reconfiguration.
Demonstrate how the object lifecycle and singleton pattern hinder flexible configuration and scalability in Scala, contrasting with class-based lifecycle and constructor parameter injection for managing dependencies.
Shift from objects to classes with a new instance cycle to control construction and wiring. Create a PostgreSQL connection with credentials, inject it into user management, and call find user.
Turn postgresql details into a class and inject them via constructor parameters to remove static cling, illustrating papic (plain old passing in classes) and growing dependency chains.
Compare runtime dependency injection with annotation-based wiring in Scala (Spring, Guice), highlighting reflection challenges, and explore compile-time alternatives that preserve type safety and performance.
Evaluate juice as a popular dependency tool, noting runtime issues and the lack of compile-time verification in Scala. Explore Scala-native alternatives with class takes and compile-time checks.
Explore the cake pattern in Scala, where layered traits and self types wire a DB access object, but compilation becomes slower as dependencies grow.
Define abstract traits for database and weather service, then implement MySQL database and weather service. Avoid using val in traits; prefer def or lazy val to prevent initialization order issues.
Pass configurations instead of raw dependencies and use implicit parameters to wire them automatically, applying the parfait pattern to group database and weather service configs.
Combine the MySQL database config and the Weather Underground service config into a single implicit object that extends both, so db access and weather access automatically receive the needed implicits.
Extend all configs with a single implicit trait to create a universal system config, reducing boilerplate and ensuring compile-time checks with the parfait pattern.
Learn how to test Scala apps by injecting mocks and fakes, swapping databases, and overriding implicits, with type safety guaranteed by the Scala compiler.
Explore the selfless trait pattern, dependency injection, and implicit configuration in Scala, using fake resources and composite objects to verify compile-time behavior and diagnose implicit errors.
explain dependency injection for objects and companion objects without constructor parameters, and show using implicit configuration in factory methods to inject dependencies and achieve compile-time verification.
Compare third-party Scala libraries like Mac Wire for compile-time guarantees against runtime injection, and evaluate the reader monad as a functional approach with performance trade-offs.
Explore current best practices and idiomatic Scala, recognizing that ideas evolve and some patterns may become deprecated, while presenting the prevailing style and fashion in the Scala community.
Explore mutability and immutability with options, recursion, and efficient collections, then master case classes, match expressions, currying, implicits, and cautions about by-name functions.
Examine how mutability, kept within scope, yields a safe Fibonacci sequence using stack memory, with no shared state escaping to the heap, and consider possible simplifications.
Explore fully functional, immutable implementations of fibonacci and factorial in Scala, using tail recursion and annotation-based optimization to achieve efficient performance without side effects.
Eliminate null references in Scala by using the Option type instead of nulls, preventing null pointer exceptions. Use map and flatMap to access optional addresses and zip codes.
Explore why mixing options and sequences in a for expression causes type errors, and learn a simple fix by converting options to a sequence for readability and easier reasoning.
Explore the Scala for expression, its generators, guards, and yield, and how it translates to flatMap and map, with file and line examples.
Learn non blocking asynchronous programming with futures, using for expressions to dereference results and move the original code into the yield block for simple asynchronous programming.
Discuss unit type and referential transparency in scala, show how side effects belong in return values, avoid procedural syntax pitfalls like missing equals, and emphasize parentheses for side-effecting methods.
Explore how to handle errors without interrupting program flow using try, and a new type that represents success or failure, plus recovery with partial functions and pattern matching.
Explore how either models success or failure with a left or right value, using right-biased map, flatMap, and case right/case left pattern matching.
Explore how the first failure in try and either cascades through system, with left projection guiding the or construct using infix notation and enabling applicative validation that accumulates all failures.
Explore strategies to replace loops with recursion using the tailrec annotation to guarantee tail call optimization in Scala, documenting and safely calling potentially infinite recursive methods while noting trampoline risks.
Explore the Scala collections library to sharpen your skills by experimenting with permutations, combinations, and other operations on this worksheet.
In Scala, explicitly declare the return type of public, non-trivial methods to avoid returning any or misinferred options, and this prevents confusing compiler errors and improves public api readability.
Use case classes in Scala to replace tuples for better type safety and readability, turning complex data like coordinates or results into named, immutable, well-typed structures.
Improve readability by replacing long if chains with a pattern match and guards for sign detection. Leverage case classes with extractors and ld result match to express linked results idiomatically.
Learn Scala's multiple parameter lists and carrying a function to a separate parameter list for cleaner syntax with curly braces, plus the loan pattern for safe file handling.
Replace implicit conversions with implicit classes to guarantee ownership, create extension methods like times, and use infix notation for readable, efficient code.
Explore how Scala sidesteps operator overloading with infix notation and symbolic method names, creating familiar operators while relying on defined precedence and avoiding abuse.
Use operators only when their meaning is obvious; otherwise name them clearly. The Cartesian operator combines three containers into a tuple for mapping, but modern practice favors tuple and map.
Learn how by-name parameters can cause eager evaluation and bugs, and adopt explicit zero-parameter functions (function0) or lazy wrappers to prevent unintended calls in Scala.
Explore design patterns and idioms in Scala, examining best practices and reusable code patterns to master idiomatic usage and design styles.
Explore design patterns from the Gang of Four and how Scala embeds them, via ADTs and type classes. Examine the loan pattern, reflection, DALS, and fluent APIs for practical use.
Explore design patterns as reusable solutions to context-specific problems, distinguish patterns from antipatterns, and recognize language shortcomings while valuing lessons from bad approaches.
Explains how the gang of four object oriented patterns map to Scala solutions, like singleton objects, abstract factory via apply, and immutable builders with case classes and copy.
Introduce algebraic data types using a sealed trait with fixed subtypes like print, false, goto, and next statements, enabling complete pattern matching and contrasting with enumerations.
Explore a recursive algebraic data type for a linked list in Scala, using empty and cons cases with head and tail, illustrating covariance and nil/:: style construction.
Explore Scala's loan pattern for automatic resource management, using with file lines and try finally to safely close resources after processing a sequence of lines. Leverage generics and type inference in a clean, robust API that avoids returning an open iterator by materializing to a list when reading small files.
Explore resource management in Scala using the Sakala arm library to automate closing of auto closable resources with managed containers, compare loan pattern alternatives, and implement buffered input-output copying.
Explore forcing the output of matches in a managed block using try, option, or either to produce success or failure, then examine simple trade patterns and a lightweight logging mixin.
Explore the selfless trait, a fully self-contained mixin with no required state. Compare importing from its companion object with extending the logger, noting how import preserves the API.
Discover how stacking traits shapes the inheritance hierarchy using linearization to visit each trait once. Build layered loggers with an abstract message, add timestamps, and color codes.
Explore a trait pattern, interface injection, that composes pure abstract traits onto classes to satisfy the closable interface at runtime, enabling stackable traits and polymorphic closable usage.
Discover how structural types simplify reflective dispatch in Scala, enabling safe calls on any value, useful for tests of private methods, and reducing reflection boilerplate, while noting possible runtime exceptions.
Explore ad hoc polymorphism with Scala type classes and build simple json converters using context bounds and implicits, culminating in composing json encoders with a Jason library.
Leverage type class composition in Scala to serialize lists and other types to Jason by supplying implicit writers, composing a list Jason writer for any type that has Jason writer.
Derive json writers for scala case classes via reflection and type tags, without macros, using a companion object pattern. Keep the type tag in the companion object to boost efficiency.
Use reflection in Scala to build a case class writer, deriving field names via the copy method and balancing derivation without macros with shapeless or magnolia options.
Learn to stringify case class instances into JSON using a type class pattern, companion object writers, and spray json, with field-name mapping and error-proof converters.
Explore using the implicit companion object to extend methods and abstract pattern type class generators, compare macros with shapeless magnolia, and consider practical, transparent alternatives to macros.
Explore Scala's domain specific languages and fluent APIs, using infix and postfix patterns with singleton types to express to be or not to be, and weigh postfix trade-offs.
Design a readable database connection interface in scala using default and named parameters with case classes and enumerations, prioritizing readability and low implementation cost.
Learn compile-time verified dependency injection in Scala, using implicit values and parameters, avoiding runtime dependency injection and macros, with alternatives like McQuire, Parfait, and Cupcake.
Use the mutable constructor pattern to safely manage mutable state during construction in a Scala test DSL, registering tests by name with by-name parameters and handling nonfatal exceptions.
Learn how to bring data in and out of the Scala type system by using XML and JSON, enforcing type information early, and applying custom extractors for free-form data.
Explore Skarner's xml support, xpath-like accessors, and xml pattern matching, then cover xml serialization, type class solutions, and json handling with Jason, including custom and regular expression extractors.
Explore how XML structures data in a library of books, journals, and DVDs using well-formed tags and nested elements, highlighting XML’s standardization role amid JSON popularity.
Learn to enable and use XML literals in Scala via the Scala XML library, load XML files with SBT builds, and access data using XPath and XML elements.
Explore XPath in scala, using slash and backslash notation to select direct children or any depth, extract books and titles from a library as a note sequence.
Explore element vs attribute xml forms, iterate xml items with for expressions, and extract book attributes (type, title) using xpath-like backslash syntax to print titles.
Explore how Scala supports XML literals and pattern matching, building XML directly in code with curly braces and using binding parameters to extract contents.
Serialize XML in and out by starting with a pure domain object and importing its fields into scope. Map a book list to XML to compose a library with boilerplate.
Demonstrates converting XML to a Book case class using XPath to extract title, author, year, and pages, with basic type casting and notes on better libraries.
Explore type classes as the answer to serialisation, assess the Scala XML data binding approach, and consider Schola Zib, SCANA XP, and Skoller XP as established libraries.
Explore json as the preferred data serialization in scala, its compactness and JavaScript readability over XML, and the landscape of scala json libraries and type-class based approaches.
Explore type-safe json parsing with play json in sbt, using JsValue and JsObject, and extract fields with as or asOpt, handling optional strings, numbers, and missing fields.
Explore practical approaches to building and validating json in scala. Use as either and validate to handle errors, and compare manual json object creation with string interpolation and parsing.
Explore printing and serializing Jassam values using pretty print or prettify and two string, comparing readable versus compact data suitable for transmission with type-safe standard definitions.
Avoid using a universal any for json serialization and demonstrate predefining serializable values for mixed types, composing numbers and strings to maintain type safety.
Build a custom JSON serializer for a person using a format with reads and writes. Compare manual field extraction and map construction to library-driven serialization and error handling.
Learn practical json serialization and deserialization by serializing person and car data, pretty printing maps, and parsing back with implicit formats, functional syntax, and macro support.
Explore macros as a compact use case, but note two downsides: you cannot customize JSON field names with macros, forcing snake_case, and macros complicate debugging since the code is generated.
Define and reuse type-class based serializers to enable two-way json serialization across case classes that hold a person, with json formatters enabling back-and-forth data and validation insights.
Explore extractors and pattern matching in Scala, using case classes and unemploy to deconstruct data beyond XML and JSON, and implement custom apply methods for product types.
Implement a custom extractor that parses a url into protocol, server, and rest using apply/unapply symmetry and option tuples for safe failure handling.
Use a custom extractor to power pattern matching on tuples, extracting web URL parts with the unemploy method, and compare parsing with regular expressions before moving to parser compensators.
Explore advanced pattern matching in Scala with an extractor called Anapolis Seek to split strings into protocol, server, and locations, handling optional values and the expansion operator.
Learn how to use regular expressions as extractors and pattern matches in Scala to parse URLs, handle optional fields with Option, and master serialization concepts.
Explore asynchronous programming in Scala using the Futures library, with practical patterns and techniques showcased in the final module of advanced part two.
Explore the life cycle of futures, compose them with map, flatMap, and for expressions, and examine promises, Java futures adaptation, retrying and patching, and alternatives that require additional dependencies.
Explore futures as a lightweight parallelism API in the Scala core libraries, learn key imports, durations, and the use of an implicit global execution context for practical, well-documented async code.
Explore futures in Scala, using duration DSL for timeouts, blocking a thread when necessary, and the future factory to run asynchronous work when ready, with a sleep-demo.
Master Scala's rules: never block or await a future, avoid blocking threads, and be careful with execution contexts; use lazy futures and an actor system to manage cancellation and shutdown.
Examine futures in Scala: unresolved versus completed futures, success and failure states, and how option Try wrappers signal outcomes, with non-blocking maps and the event model.
Explore asynchronous programming in Scala by composing futures, mapping work, and propagating failures without blocking the main thread, including practical patterns for success and recovery.
Explore how to compose asynchronous computations in Scala using futures, maps, and flat maps, then optimize with for expressions and address the gotcha when futures depend on each other.
Dereference values inside the for block to yield the same results and return a future, enabling asynchronous execution without thread blocking or event handling.
Learn to avoid blocking threads with sleep, wait for futures at the top level using await with a duration DSL timeout, and compare Await.ready with Await.result to surface exceptions.
Explore future operations beyond map and flatMap, including filter, collect, and transform, to narrow types with partial functions, handle success and failure, and recover from errors.
Explore and then on patterns for futures to trigger side effects after resolution without changing the result, fire-and-forget messages or closing a file handle, with foreach and F7.
Explore how to handle failed futures with recovery in Scala, using fallbacks, recover, and recover with a partial function to replace the result of another future.
Learn to manage multiple futures with for expression, future.sequence, and traverse to produce a single future of a list of results from parallel square operations.
Learn operations on future sequences, including first completed of for the fastest result, and fold left versus reduce left with empty sequences and potential future failures.
Explore how futures and promises form an asynchronous client-server channel in Scala, linking promise and future across networks with ARCA and VMs, including broken promises.
Explore patterns for handling promises in async code, and learn how a broken promise yields an exception and a failed future. Demonstrate real-world implementations of these concepts in practice.
Adapt asynchronous events with promises to create non-blocking, event-driven flows, completing a promise as external futures finish, and convert Java futures to Scala futures for interoperability.
Apply a batching pattern to scalable futures in Scala, throttling concurrent work to avoid file handle exhaustion and API overload by processing in small batches (e.g., 100 at a time).
Batch a large list into smaller batches and process them asynchronously, returning a single vector of results. Fold over batches, ensuring each batch finishes before the next—essential reusable async pattern.
Learn how to implement asynchronous retry with futures to avoid blocking on external services, using a simple example that simulates repeated failures before a success.
Compare a naive fixed-retry approach to more robust async retry patterns, introducing backoff and server backoff concepts, and planning better fallbacks for failed calculations.
Explore a configurable retry pattern for futures: recursive retries with a decrementing counter and recover with on failure, illustrated by three and five retry counts.
Implement a non-blocking retry backoff pattern using an actor system scheduler to retry a failing operation with a sequence of delays, until the backoff sequence is exhausted.
Terminate active systems to prevent applications from hanging. Call the terminate method in your main method when you exit the program.
Explore futures, future patterns, and tasks, highlighting the futures API's ubiquity, performance, and documentation, and learn conversions between tasks and futures and their added capabilities.
The Escalate Software Scala Advanced course is intended for experienced Scala developers looking to improve their skills, particularly for library and API design and development. It covers topics needed to be effective in producing high quality, correct, powerful and flexible Scala libraries that are still easy to use by others.
Part 2 provides advice on best practices and patterns drawn from many years of real-world experience in Scala programming. In addition, strategies for compile-time verified dependency injection are covered, then XML and JSON serialization and deserialization, the use of custom extractors for pattern matching, and finally the very popular and important topic of asynchronous programming using Scala Futures:
Dependency Injection
Idioms and Best Practice advice
Patterns - Gang of Four
Scala specific patterns
XML literals and features
JSON libraries and type-classes
Custom extractors in pattern matching
Futures
Future functions and combinators
Patterns with Futures
It is recommended that you complete Scala Advanced part 1 before taking this part. While not strictly necessary, we may assume knowledge from part 1 in some of the explanations that could be hard to follow unless you know the material.
Part 3 (following this) builds on the information in these first two parts of the advanced course and moves into more advanced functional programming topics, along with performance optimization and more.