Effective Scala

Categories:

Recommended

Introduction

Scala is one of the main application programming languages used at Twitter. Much of our infrastructure is written in Scala and we have several large libraries supporting our use. While highly effective, Scala is also a large language, and our experiences have taught us to practice great care in its application. What are its pitfalls? Which features do we embrace, which do we eschew? When do we employ “purely functional style”, and when do we avoid it? In other words: what have we found to be an effective use of the language? This guide attempts to distill our experience into short essays, providing a set of best practices. Our use of Scala is mainly for creating high volume services that form distributed systems — and our advice is thus biased — but most of the advice herein should translate naturally to other domains. This is not the law, but deviation should be well justified.

Scala provides many tools that enable succinct expression. Less typing is less reading, and less reading is often faster reading, and thus brevity enhances clarity. However brevity is a blunt tool that can also deliver the opposite effect: After correctness, think always of the reader.

Above all, program in Scala. You are not writing Java, nor Haskell, nor Python; a Scala program is unlike one written in any of these. In order to use the language effectively, you must phrase your problems in its terms. There’s no use coercing a Java program into Scala, for it will be inferior in most ways to its original.

This is not an introduction to Scala; we assume the reader is familiar with the language. Some resources for learning Scala are:

This is a living document that will change to reflect our current “best practices,” but its core ideas are unlikely to change: Always favor readability; write generic code but not at the expensive of clarity; take advantage of simple language features that afford great power but avoid the esoteric ones (especially in the type system). Above all, be always aware of the trade offs you make. A sophisticated language requires a complex implementation, and complexity begets complexity: of reasoning, of semantics, of interaction between features, and of the understanding of your collaborators. Thus complexity is the tax of sophistication — you must always ensure that its utility exceeds its cost.

And have fun.

Formatting

The specifics of code formatting — so long as they are practical — are of little consequence. By definition style cannot be inherently good or bad and almost everybody differs in personal preference. However the consistent application of the same formatting rules will almost always enhance readability. A reader already familiar with a particular style does not have to grasp yet another set of local conventions, or decipher yet another corner of the language grammar.

This is of particular importance to Scala, as its grammar has a high degree of overlap. One telling example is method invocation: Methods can be invoked with “.”, with whitespace, without parenthesis for nullary or unary methods, with parenthesis for these, and so on. Furthermore, the different styles of method invocations expose different ambiguities in its grammar! Surely the consistent application of a carefully chosen set of formatting rules will resolve a great deal of ambiguity for both man and machine.

We adhere to the Scala style guide plus the following rules.

Whitespace

Indent by two spaces. Try to avoid lines greater than 100 columns in length. Use one blank line between method, class, and object definitions.

Naming

Use short names for small scopes
is, js and ks are all but expected in loops.
Use longer names for larger scopes
External APIs should have longer and explanatory names that confer meaning. Future.collect not Future.all.
Use common abbreviations but eschew esoteric ones
Everyone knows okerr or defn whereas sfri is not so common.
Don’t rebind names for different uses
Use vals
Avoid using `s to overload reserved names.
typ instead of `type`
Use active names for operations with side effects
user.activate() not user.setActive()
Use descriptive names for methods that return values
src.isDefined not src.defined
Don’t prefix getters with get
As per the previous rule, it’s redundant: site.count not site.getCount
Don’t repeat names that are already encapsulated in package or object name
Prefer:

object User {
  def get(id: Int): Option[User]
}

to

object User {
  def getUser(id: Int): Option[User]
}

They are redundant in use: User.getUser provides no more information than User.get.

Imports

Sort import lines alphabetically
This makes it easy to examine visually, and is simple to automate.
Use braces when importing several names from a package
import com.twitter.concurrent.{Broker, Offer}
Use wildcards when more than six names are imported
e.g.: import com.twitter.concurrent._
Don’t apply this blindly: some packages export too many names
When using collections, qualify names by importing scala.collection.immutable and/or scala.collection.mutable
Mutable and immutable collections have dual names. Qualifiying the names makes is obvious to the reader which variant is being used (e.g. “immutable.Map“)
Do not use relative imports from other packages
Avoid

import com.twitter
import concurrent

in favor of the unambiguous

import com.twitter.concurrent
Put imports at the top of the file
The reader can refer to all imports in one place.
Category:

Attribution

Marius Eriksen ,Effective Scala, URL: https://twitter.github.io/effectivescala/

This work is licensed under the Attribution 3.0 Unported (CC BY 3.0):
(https://creativecommons.org/licenses/by/3.0/
).

VP Flipbook Maker

Convert your work as digital flipbook with Visual Paradigm Online Flipbook Maker! You can display your work in an attractive way. Moreover, you can customize your work with its design tool. Try it now!