Scala in practice

@donatasm

About me

  • Originally C# developer @adform
  • Deploying Scala to production for the last 2 years

How did that happen?

Or why would a C# developer search for something beyond .NET?

Online advertising

Scaling is hard

Running everything on Windows and .NET

  • Everything is possible, if you try hard
  • Usually, what you need is already done by someone, but:
    • works only on Linux, or
    • "use at your own risk on Windows", or
    • is not implemented in .NET

..., for example

  • Deployment*
    • Puppet, Docker
  • Fast, scalable and awesome data stores*
    • Cassandra, Aerospike, Vertica, Redis, Kafka
  • High performance libraries and frameworks*
    • clients for the data stores, networking, data processing

* may not be true anymore

Why JVM?

  • Runs everywhere
  • Huge ecosystem of open-source libraries and frameworks

Why not _?

  • Java
  • Clojure
  • Groovy, JRuby, Jython

Quick facts about Scala

  • A scalable language, released in 2004
  • Object-oriented and functional
  • Statically typed with very strong type system
  • Current version 2.11.8

Hello, world!

C#


public static class Hello
{
	public static void Main(string[] args)
	{
		Console.WriteLine("Hello, world!");
	}
}
					

Scala


object Hello {
	def main(args: Array[String]) {
		println("Hello, world!")
	}
}
					

Syntax

C#


interface I {}
class B<T> {}
class A : B<String>, I
{
	int MyMethod() { return 42; }
}
					

Scala


trait T
class B[T]
class A extends B[String] with I {
	def myMethod = 42
}
					

Variables

Scala supports two types of variable declarations:

var declares a variable like in C#


var name = "world"
name = name + "!"
					

val declares a read-only value


val name = "world"
name = name + 1 // ERROR
					

Lazy vals

Scala


lazy val resource = resourceExpensiveToCreate()
					

C#


Lazy<Resource> resource =
	new Lazy<Resource>(
		() => ResourceExpensiveToCreate(),
		isThreadSafe = true);
					

Methods


class Hello {
	def sayTo(name: String): String = {
		return s"Hello, $name"
	}
}
					

class Hello {
	def sayTo(name: String) = s"Hello, $name"
}
					

Methods


val hello = new Hello
hello.sayTo("world")
					

val hello = new Hello
hello sayTo "world"
					

Defining data transfer objects in C#


public sealed class Product
{
	private readonly string _name;
	private readonly string _category;
	private readonly int _price;

	public Product(string name, string category, int price)
	{
		_name = name;
		_category = category;
		_price = price;
	}

	public string Name { get { return _name; }}
	public string Category { get { return _category; }}
	public int Price { get { return _price; }}

	public override bool Equals(object other)
	{
		if (ReferenceEquals(null, other)) return false;
		if (ReferenceEquals(this, other)) return true;
		var o = (Product)other;
		return o._name == _name
			&& o._category == _category
			&& o._price == _price;
	}

	public override int GetHashCode()
	{
		// magic using number 37, usually generated by tool
	}
}
					

Defining data transfer objects (DTO) in Scala


case class Product(name: String, category: String, price: Int)
					

val p1 = Product("product1", "category1", 99)
val p2 = Product("product1", "category1", 99)
val p3 = Product("product2", "category2", 100)
println(p1)
println(p1 == p2)
println(p2 == p3)
println(p1.price)
					

Product(product1, category1, 99)
true
false
99
					

Transforming DTO in C#


public static class ProductJson
{
	public static JsonObject ToJson(this Product product)
	{
		return new JsonObject(
			new JsonProperty("name", product.Name),
			new JsonProperty("category", product.Category),
			new JsonProperty("price", product.Price)
		);
	}
}
					

And then:


var json = new Product("name", "category", 101).ToJson();
					

Scala implicit conversions


object ProductJson
{
	implicit def toJson(product: Product): JsonObject =
		JsonObject(
			JsonProperty("name", product.Name),
			JsonProperty("category", product.Category),
			JsonProperty("price", product.Price)
		)
}
					

And then:


val json: JsonObject = Product("name", "category", 101);
					

Scala implicit parameters


case class User(id: Int)

class UserRepository {
  def getUserById(id: Int): User = {
    // call to database
  }
}

class UserService {
  def getUserById(id: Int, repository: UserRepository): User = {
    repository.getUserById(id)
  }
}
					

And then:


val repository = new UserRepository()
val service = new UserService()

service.getUserById(1, repository)
					

Scala implicit parameters


class UserService {
  def getUserById(id: Int)(implicit repository: UserRepository): User = {
    repository.getUserById(id)
  }
}
					

And then:


implicit val repository = new UserRepository()
val service = new UserService()

service.getUserById(1)
					

Functions, Actions

C#


Action a1 = () => {};
Action<int> a2 = (int i) => {};
Func<int> f1 = () => 0;
Func<int, int> f2 = (int i) => 0;
					

Scala


val a1 = () => {}
val a2 = (i: Int) => {}
val f1 = () => 0
val f2 = (i: Int) => 0
					

LINQ

C#


var n = Enumerable.Range(1, 10);
n.Select(i => i*i);
n.Where(i => i%2 == 0);
n.Take(3);
n.Count();
n.Distinct();
n.Sum();
					

Scala


val n = 1 to 10
n.map(i => i*i)
n.filter(i => i%2 == 0)
n.take(3)
n.size
n.distinct
n.sum
					

That's (almost) it

  • Convert Java or C# code line by line to Scala, and...
  • you'll have beautiful code. Win!

Tests, for example


test("four bids with the same price, winner is randomized") {
  val adSlot = AdSlot(id = "1", minPrice = Money(1))
  val adSlots = Set(adSlot)
  val bidResponses = List(BidResponse("bidder", bids()))

	val results = (1 to 1000)
	  .map(_ => auctioneer.winningBids(adSlots, bidResponses).head)
	  .groupBy(_.bid)
	  .map { case (_, bids) =>  bids.toSeq.length / 1000.0 }

  all(results) should equal(0.25 +- 0.01)
}
					

Tests, for example


it should "return 400 when request headers " +
  "too large" in withNginxBidder { bidder =>

  val headers = (1 to 8192)
		.map(i => RawHeader(s"X-Header-$i", i.toString))

  val response = bidder
    .client
    .send(Get(s"http://localhost:$nginxPort/")
    .withHeaders(headers: _*))

  response should equal (HttpResponse(400, HttpEntity.Empty,
    List(`Content-Length`(0), Connection("close"))
  ))
}
					

Or DSL for rendiring html


def statsPresentation(stats: Stats) = HttpResponse(
  entity = HttpEntity(`text/html`,
	<html>
	  <body>
    <h1>HttpServer Stats</h1>
    <table>
      <tr><td>days:</td><td>{stats.uptime.toDays}</td></tr>
      <tr><td>hours:</td><td>{stats.uptime.toHours}</td></tr>
      <tr><td>minutes:</td><td>{stats.uptime.toMinutes}</td></tr>
      <tr><td>totalRequests:</td><td>{stats.totalRequests}</td></tr>
    </table>
	  </body>
	</html>.toString))
					

Or abuse it

When you see this...

					
val result = (0 /: |)(_ + _)
					
					
					
val | = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
					
					
					
val list = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
val result = list.foldLeft(0)(x, y => x + y)
// result = 45
					
					

Patterns

Cake Pattern

The famous pattern of doing DI in Scala

Classical example


case class Size(width: Int, height: Int)
case class Ad(id: Int, size: Size)

trait AdRepository {
  def get(id: Int): Ad
  def find(size: Size): Ad
}
					

Wrap it into component


trait AdRepositoryComponent {
  def adRepository: AdRepository

  trait AdRepository {
    def get(id: Int): Ad
    def find(size: Size): Ad
  }
}
					

Dependency defined as self-type annotation


// self-type annotation
trait Bidder { this: AdRepositoryComponent =>

  def getAd(id: Int): Ad =
    adRepository.get(id)

  def matchAd(size: Size): Ad =
    adRepository.find(size)
}
					

Concrete implementation


trait MySqlAdRepositoryComponent extends AdRepositoryComponent {
  def adRepository = new MySqlAdRepository

  class MySqlAdRepository extends AdRepository {
    override def get(id: Int): Ad = {
      // TODO: get from database
    }

    override def find(size: Size): Ad = {
			// TODO: get from database
    }
  }
}
					

Finally, wiring it up


class DefaultBidder extends Bidder with MySqlAdRepositoryComponent

object BidderApplication {
  def main(args: Array[String]): Unit = {
    val bidder = new DefaultBidder
    // ...
  }
}
					

Testing


class BidderTest extends Bidder with AdRepositoryComponent {
  lazy val adRepository: AdRepository = mock[AdRepository]

	// TODO: write some tests
}
					

Classical constructor injection, pimped with implicits


class DefaultBidder(implicit val repository: AdRepository)

object BidderApplication {
  def main(args: Array[String]): Unit = {
    implicit val repository = new MySqlAdRepository
    val bidder = new DefaultBidder
    // ...
  }
}
					

Yes, but this is Java'ish code!

Scala is also great for OOP

Thank you!

QA