Introduction to the Course Path

Welcome to the course path for Refactoring Techniques in Scala 3. Before we begin the first course, let's discuss the themes of this course path, what we will cover, and how we will approach our practice sessions.

Our journey will focus on equipping us with the skills to confidently modify existing codebases while minimizing the risk of introducing bugs. By the end of this course, we'll be well-versed in various strategies to make our code more testable and reliable using Scala 3 and its powerful features.

Challenges in Established Codebases

Working with established codebases often presents unique challenges. These include dealing with tightly coupled components, a lack of documentation, and the fear of breaking existing functionality when making changes. Without the use of proper tools and techniques, even minor modifications can lead to unexpected issues.

Tools Used Within This Course Path

As we progress through the path, we will be using a few Scala libraries to help us along the way. While they are going to be used extensively within this course, keep in mind that they are just some of the options available out there, and that other projects might use different tools. The point is to understand why we use them, not the particular tool.

We'll be using ScalaTest, a popular testing framework, to write and run tests effectively. Refactoring will be a significant focus, as it helps increase testability by creating traits and breaking down dependencies. We'll also explore the use of Mockito, a mocking library, to isolate and test components without external dependencies.

Topics Covered Within This Course Path

All courses will work with an existing codebase. This means that we will always start with some existing state and will use it to demonstrate a concept, technique, or strategy.

The first course will revolve around writing tests and enhancing testability. The second course will go deeper into breaking dependencies and how to use dependency injection and inversion of control in a practical way using Scala's features. The third course will cover how to discover and use seams to enable testability and expand capabilities, while the last course will talk about sprout and wrap techniques for refactoring.

Practical Application with an Order Processor

To make these concepts tangible, we'll use an order processor as our central example throughout the vast majority of our lesson and practice sessions. This practical application will serve as a playground for applying the techniques learned. By working through real-world scenarios, we'll gain a deeper understanding of how to implement these strategies in our own projects.

This is one example of how the order processor might look:

Scala
1import java.time.LocalDateTime 2 3case class OrderItem(price: BigDecimal, quantity: Int) 4case class Order(items: List[OrderItem], orderTotal: BigDecimal = BigDecimal(0), processedAt: Option[LocalDateTime] = None) 5 6class OrderProcessor: 7 def processOrder(order: Order): Order = 8 val totalAmount = order.items.map(item => item.price * item.quantity).sum 9 order.copy( 10 processedAt = Some(LocalDateTime.now), 11 orderTotal = totalAmount 12 )

Depending on the topic at hand, the order processor will be contrived to best demonstrate said topic, hopefully helping us grasp the concepts discussed.

Summary

Now that we have covered the basics, let's look at an intro practice session aimed at getting us familiar with our practice playground.

Let's move on to see the first version of the order processor using Scala and ScalaTest.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal