Scala Best Practices

Table of contents
Reading Time: 6 minutes

The central drive behind Scala is to make life easier and more productive for the developer — and that includes me. Scala does this with three principal techniques: It cuts down on boilerplate, so programmers can concentrate on the logic of their problems. It adds expressiveness, by tightly fusing object-oriented and functional programming concepts in one language. And it protects existing investments by running on the Java Virtual Machine and interoperating seamlessly with Java.

In this blog, we will see what are some necessary points every developer should keep in mind while coding in scala and make the best use of Scala    

     Points to remember for Scala beginners:

  1. SHOULD enforce a reasonable line length: A long line makes it difficult to ascertain where the line starts or ends and it makes it difficult to continue on the next line below it, as your eyes have to move a lot from the right to the left. It also makes it difficult to scan for important details.So as a balance:
    • strive for 80 chars as the soft limit and if it gets ugly,
    • then 100 chars are enough, except for …
    • function signatures, which can get really ugly if limited
  2. MUST NOT rely on a SBT or IDE plugin to do the formatting for you: IDEs and SBT plugins can be of great help, however, if you’re thinking about using one to automatically format your code, beware.There is no plugin that is able to infer the developer’s intent, since that requires a human-like understanding of the code and would be near impossible to make. The purpose of proper indentation and formatting isn’t to follow some rigid rules, but to make the code more logical, more readable, more approachable.
  3. SHOULD break long functions: Functions should only be a couple of lines long. If the no. of lines get too big, then we need to break them into smaller functions and give them a name.The purpose here is to primarily aid readability, so in Scala, we can do inner-functions to break logic into pieces, a function should not have more than 30 LOC.
  4. Names MUST be meaningful: Be it variable name, method name or class name, names should be self-descriptive.You can be concise in naming if the type/purpose can be easily inferred from the immediate context, or if there’s already an established convention. For example, val transformedValue = for (p <- people) yield  someFunction(p) 
  5. SHOULD use immutable data structures: To reduce the use of mutable objects and data structures in your code. Try to use vals, immutable objects and methods without side-effects.There are two components to “prefer immutability”:
    • Prefer immutable collections. For instance, use immutable sequences like List and Vector before reaching for the mutable ArrayBuffer.
    • Prefer immutable variables. That is, prefer val to var.

    There are at least two major benefits to using immutable variables (val) and immutable collections:

    • They represent a form of defensive coding, keeping your data from being changed accidentally.
    • They’re easier to reason about.

     

  6. MUST NOT use “return”: The return statement from Java signals a side-effect – unwind the stack and give this value to the caller. In a language in which the emphasis is on side-effect-full programming, this makes sense. However, Scala is an expression oriented language in which the emphasis is on controlling/limiting side-effects.
  7. MUST NOT use “null”: You must avoid using null. Prefer Scala’s Option[T] instead. Null values are error prone because the compiler cannot protect you. Nullable values that happen in function definitions are not documented in those definitions.The point of using Option[T] is that the compiler forces you to deal with it, one way or another:
    • you either have to deal with it right away (e.g. by providing a default, throwing an exception, etc..)
    • or you can propagate the resulting Option up the call stack
  8. MUST NOT use “Option.get” (Instead you can use fold or getOrElse : Using fold is preferred as it provides type safety) : Consider the following example:val someValue: Option[Double] = ???
    You might be tempted to do this:
    val result = someValue.get + 1
    Never do that, as there are chances of getting NullPointerException for a NoSuchElementException and that defeats the purpose of using Option in the first place.Alternatives:
    1. using Option.getOrElse
    2. using Option.fold
    3. using pattern matching and dealing with the None branch explicitly


  9. SHOULD NOT use Any or AnyRef or isInstanceOf / asInstanceOf : Avoid using Any or AnyRef or explicit casting, unless you’ve got a really good reason for it. Scala is a language that derives value from its expressive type system, usage of Any or of typecasting represents a hole in this expressive type system and the compiler doesn’t know how to help you there.

  10. MUST NOT use magic values: Although not uncommon in other languages to use “magic” (special) values like -1 to signal particular outcomes, in Scala there is– a range of types to make intent clear. Option, Either, Try are examples. Also, in case you want to express more than a boolean success or failure, you can always come up with an algebraic data type. 
  11. Public functions SHOULD have an explicit return type : def someFunction(param1: T1, param2: T2): Result = {
      ???
    }
    To this:def someFunction(param1: T1, param2: T2) = {
      ???
    }
    Yeah, type inference on the result of a function is great and all, but for public methods:
    1. it’s not OK to rely on an IDE or to inspect the implementation in order to see the returned type
    2. Scala currently infers the most specialized type possible, because in Scala the return type on functions is covariant, so you might actually get a really ugly type back


  12. SHOULD NOT define case classes nested in other classes: You should never define nested case classes inside another object/class because it messes with Java’s serialization. The reason is that when you serialize a case class it closes over the “this” pointer and serializes the whole object, which if you are putting in your App object means for every instance of a case class you serialize the whole world.And the thing with case classes specifically is that:
    1. one expects a case class to be immutable (a value, a fact) and hence
    2. one expects a case class to be easily serializable.

But Sometimes even after being aware of all these practices, developers may make mistakes. So we would require something which could force us to ensure all these standards.

Available tools in the market for scalastyle check:

  1. Scalastyle SBT plugin
  2. Codacy can be linked to your project

Now we will discuss how you can use Scalastyle Sbt Plugin in your projects:

addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "0.8.0")

And you need to provide scalastyle-config.xml in the root of your project.

To setup this plugin in a multi-module project, you can refer this blog

Usage

You will need a configuration file. The easiest way to get one is to use the below command:

sbt scalastyleGenerateConfig

This will generate a file named scalastyle-config.xml in the directory in which you executed this command with some default set of rules.(Prefer to choose root of your project).

Scalastyleconfig.xml will somewhat look like this with a lot of checks. A small snippet is given below:



This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters


<scalastyle>
<name>Scalastyle standard configuration</name>
<check level="warning" class="org.scalastyle.file.FileLengthChecker" enabled="true">
<parameters>
<parameter name="maxFileLength"><![CDATA[800]]></parameter>
</parameters>
</check>
<check level="warning" class="org.scalastyle.file.FileLineLengthChecker" enabled="true">
<parameters>
<parameter name="maxLineLength"><![CDATA[160]]></parameter>
<parameter name="tabSize"><![CDATA[4]]></parameter>
</parameters>
</check>
<check level="warning" class="org.scalastyle.scalariform.ReturnChecker" enabled="true"></check>
<check level="warning" class="org.scalastyle.scalariform.NullChecker" enabled="true"></check>
<check level="warning" class="org.scalastyle.scalariform.MethodNamesChecker" enabled="true">
<parameters>
<parameter name="regex"><![CDATA[^[a-z][A-Za-z0-9]*$]]></parameter>
</parameters>
</check>
</scalastyle>
view raw

gistfile1.txt

hosted with ❤ by GitHub

Understand how scalastyle-config.xml works for our project

We always find the rules in scalastyle-config.xml to check our code quality and standards.

Let us consider the below check:

It warns you for every magic number in your project.

Another example is :  

It warns you for every null you use in your project.

If you will have a closer look at the class being used in the rules: (Example: org.scalastyle.scalariform.NullChecker). You can observe that every rule class reside in scalaiform.

This gives a clear impression that if you would like to add a custom rule in your scalastyle-config.xml

Creating your jar :

If you want to include an XYZ check, you need to create a class :

package org.ext

// check that we don’t use foobar
class NoXyzChecker extends ScalariformChecker {
 val errorKey = “dont.use.Xyz”

 final def verify(ast: CompilationUnit): List[ScalastyleError] = {
   List() // details left as an exercise for the reader
 }
}

Please note that errorKey val is : dont.use.Xyz

In addition to the above class, you will also need to create: reference.conf which needs to be present at the top level of your Jar.

Your reference.conf for the above rule should look something like this :

dont.use.Xyz.message = “Avoid using Xyz”
dont.use.Xyz.label = “Xyz”
dont.use.Xyz.description = “Check that Xyz is not used”

Note: You can have more than one rule in the jar, but you’ll need a single reference.conf with all of the messages for your rules.

And lastly, you need to include your jar in your project and add the rule in your scalastyle-config.xml.

To see step by step guide for this, you can refer this blog

Hope, this blog will help you. 🙂

References:

  1. http://www.scalastyle.org/custom-rules.html
  2. https://github.com/alexandru/scala-best-practices

knoldus-advt-sticker


Written by 

I am a Software Consultant and has experience of more than 1.5 years. I like to study and write about latest technologies.