Chapter 6
Scala Style/Lint

Code smell is often defined “as certain structures in code that indicate violation of fundamental design principles and negatively impact design quality.” Code smells are not bugs, but instead are indications that the structure of code hasn't been fully fleshed out, or was rushed to accommodate features at the cost of code quality. These are indications of a weakness in design and must be handled with a good eye, equally good coding habits, and help from strong style/lint tooling.

This translates to testing your Scala application, meeting its functional and business requirements, and also working to ensure that your code has no structural problems. Luckily, the open source world has created some extremely well programmed and maintained styling/lint tooling for Scala. You can use them to increase the reliability and efficiency of your applications/services, in effect allowing your code over its life cycle to become easier to maintain, understand, and extend.

This chapter takes you through the setting up of the most popular tools for styling and linting. It will also show you how to automate linting, and give your code the best possible chance to stay within current coding conventions.

SCALA WITH STYLE

The first tool to integrate into this book's sample project is a little plugin called scalastyle (http://www.scalastyle.org/). Scalastyle “examines your Scala code and indicates potential problems with it.” This can become very beneficial, since new code and more sections are added. To start working with scalastyle, your best bet is to install the SBT plugin by adding the following to your project/plugins.sbt:

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

You'll need to then run the following command to generate the scalastyle-config.xml into the root directory:

sbt scalastyleGenerateConfig

After that file has been generated you can take a look into it and note that any of the rules can be modified to fit your individual needs. For a full breakdown of those rules, you can check out the Scalastyle: Implemented Rules page located here: http://www.scalastyle.org/rules-0.8.0.html. You can now run sbt scalastyle, which will generate a target/scalastyle-result.xml that also gives back feedback in the CLI for any style errors that arise during the check.

One of the nicer features of scalastyle is the ability to share a single scalastyle configuration file across multiple projects by supplying a scalastyleConfigUrl in your build SBT. Typically, you can use the s3cmd to connect to a private s3 bucket, which can be set up similar to the example from the scalastyle documentation:

lazy val updateScalaStyle = taskKey[Unit]("updateScalaStyle")

updateScalaStyle := {
  val secretKey = sys.env.get("S3_SECRET_KEY")
  val accessKey = sys.env.get("S3_ACCESS_KEY")
  val configUrl = "s3://bucket_name/configs/scalastyle-config.xml"
  (secretKey, accessKey) match {
    case (Some(sk), Some(ak)) =>
      val result: Int = file("target/scalastyle-config.xml") #< s"s3cmd
        --secret-key=$sk --access-key=$ak get $configUrl" !

    case _ =>
      println(s"Was unable to retrieve secretKey: $secretKey or accessKey:
        $accessKey from system variables")
  }
}

This will attempt to grab the Scala style configuration file from s3 when you execute the updateScalaStyle task. You can also automate the task during a compile or test run by adding the following:

(scalastyle in Compile) <<= (scalastyle in Compile) dependsOn updateScalaStyle

(scalastyle in Test) <<= (scalastyle in Test) dependsOn updateScalaStyle 

Another customization feature that is available to you is the ability to create your own rules and add them inside the scalastyle-config.xml. To accomplish this it can be helpful to create a utility class within the project using scalastyle.

SCALIFORM

Scaliform is a code formatting utility, which can be used to keep all of your code in a single style. With a wide range of configuration options, any Scala project can immediately benefit by adding this dependency. The library can be used as a standalone CLI tool available here: https://github.com/scala-ide/scalariform. Or it can be integrated into SBT through a plugin by adding the following to your projects build SBT file:

resolvers += "Sonatype OSS Releases" at "https://oss.sonatype.org/service/
  local/staging/deploy/maven2"

addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.6.0")

After this, you can start up SBT and run the following:

sbt scalariformFormat

This will go through the code in your project and format according to the default settings of scaliform. Usually it's worth some discussion within your team before applying styling and coming to a consensus for which advanced options you may want to include in the code base for a meaningful discussion.

The below advanced configuration has resulted in the least amount of bikeshedding, since the styling is conservative enough not to raise many issues.

//build.sbt
import scalariform.formatter.preferences._
import com.typesafe.sbt.SbtScalariform

SbtScalariform.scalariformSettings

ScalariformKeys.preferences := ScalariformKeys.preferences.value
  .setPreference(AlignSingleLineCaseStatements, true)
  .setPreference(DoubleIndentClassDeclaration, true)
  .setPreference(placeScaladocAsterisksBeneathSecondAsterisk, true)
  .setPreference(IndentLocalDefs, true)
  .setPreference(IndentPackageBlocks, true)
  .setPreference(IndentSpaces, 2)
  .setPreference(MultilineScaladocCommentsStartOnFirstLine, false)

The phrase SbtScalariform.scalariformSettings will by default start formatting your project when the compile task or test:compile is run. If you only want to use Scalariform when invoked, make sure you use defaultScalariformSettings instead. This can be helpful if you don't want to have your code restructuring itself after every compile. That said, when using editors like vim or sublime, it can be a reassuring sight to see your code automatically reformatting itself after you save while having a watch on the compile task.

SCAPEGOAT

Another popular lint tool for your arsenal is Scapegoat, a younger project than scalastyle, but with some great linting operations (and a huge list of 107 inspections) that can benefit any code base. Scapegoat will find issues with code and report them to the console and generate html/xml reports that can give you some good feedback in your browser.

To install, you only need to add the autoplugin to your project/plugin.sbt:

addSbtPlugin("com.sksamuel.scapegoat" %% "sbt-scapegoat" % "1.0.4")

Now specify the version in your build via:

scapegoatVersion := "1.1.0"

Now you only need to invoke the scapegoat task in SBT to have it generate the above reports, which you'll find in target/scala-2.11/scapegoat-report. The scapegoat task by default will regenerate those reports after each invocation, but you can customize the report generation to only account for changes between runs by changing the setting scapegoatRunAlways to false.

One of the nice features of Scapegoat is the ability to suppress a warning by using the java.lang.SuppressWarning annotation around any method that you want the linter to skip over. This can be beneficial when you're aware that the code you're writing is breaking the rules, but that it is for the greater good.

Class Temp {
  @SuppressWarnings(Array("BigDecimalDoubleConstructor"))
  def test() = {
    val x: BigDecimal = BigDecimal(1.2)
    x
  }
}

The reason to like scapegoat is because it does one thing really well. It checks your code for structural errors and announces them loudly when you run the scapegoat task. It gives you immediate feedback, which is good to have on any project that doesn't already have any structural analysis tooling.

WARTREMOVER

Probably the easiest to customize out of the lint tools reviewed so far, WartRemover is a stable inclusion into your linting stack. First install the SBT plugin:

addSbtPlugin("org.brianmckenna" % "sbt-wartremover" % "0.14")

When running WartRemover for the first time, all of the checks and patterns are turned off by default. This allows you to slowly start leveling up the heat on what “warts” you want to start verifying and fixing. You can do this by adding a small configuration to the build.sbt.

wartremoverErrors ++= Warts.unsafe

Then it's only a matter of running run or compile and getting feedback from the compiler. If you want to ensure that things were configured properly, run the task wartremoverErrors, which shows you a list of warts that have been loaded into SBT. You can also add a quick wart to your code to test that the auto-plugin has hooked in properly:

var i = 100

Now compile and watch WartRemover do its magic.

Aside from the quick setup of WartRemover, you can take a quick tour of the current list of warts by visiting https://github.com/puffnfresh/wartremover, or start creating your own. Following the example provided by the WartRemovers github page, let's break down what it's doing to create your own:

//full example
import org.brianmckenna.wartremover.{WartTraverser, WartUniverse}

object Unimplemented extends WartTraverser {
  def apply(u: WartUniverse): u.Traverser = {
    import u.universe._
    import scala.reflect.NameTransformer

    val notImplementedName: TermName = NameTransformer.encode("???")
    val notImplemented: Symbol = typeOf[Predef.type].member(notImplementedName)
    require(notImplemented != NoSymbol)
    new Traverser {
      override def traverse(tree: Tree) {
        tree match {
          case rt: RefTree if rt.symbol == notImplemented =>
            u.error(tree.pos, "There was something left unimplemented")
          case _ =>
        }
        super.traverse(tree)
      }
    }
  }
}

During execution of the above code, WartTraverser is going to check out any code that has a method that is implementing ??? and throws an error with the line stating “There was something left unimplemented.” If you are not familiar with the Scala reflection libraries, you can get some background by checking out the Scala documentation here: http://docs.scala-lang.org/overviews/reflection/symbols-trees-types.html. This will give you some insight into the require statement from the above code snippet:

require(notImplemented != NoSymbol)

NoSymbol is “is commonly used in the API to denote an empty or default value.”

val notImplementedName: TermName = NameTransformer.encode("???")
val notImplemented: Symbol = typeOf[Predef.type].member(notImplementedName)
require(notImplemented != NoSymbol)

This is working as a guard to detect that the method contains that ??? symbol. While this can be a little confusing when you first start to implement your own warts or anti-pattern checks in your code base, it can become highly beneficial.

SCOVERAGE

Statement coverage is a white box testing technique, which involves the execution of all the statements at least once in the source code. It is a metric, which is used to calculate and measure the number of statements in the source code that have been executed. Why would you want that in Scala? Often in your Scala statements you may end up creating a truly magnificent one liner. It is one of those one-liners that may impress your friends, like so (adapted from http://rosettacode.org/wiki/FizzBuzz#One-liner_geek):

def fizzBuzz(): Seq[String] = for (i <- 1 to 100) yield(Seq(15 -> "FizzBuzz",
  3 -> "Fizz", 5 -> "Buzz").find(i % _._1 == 0).map(_._2).getOrElse(i.toString))

Since so much is going on in this line, getting back information about if this line is covered through a test is nearly impossible. You should split the functionality up and create a unit test that is able to test each of the sections. However, thanks to Scoverage you won't have too.

Basically, all you have to do is write regular unit tests! Then, Scoverage (a tool that offers aforesaid statement and branch coverage) can be used to give you a report of how much of your code base has been covered.

The setup is straightforward. First, you add:

addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.3.5")

Then you go into the SBT console and type coverage and then type test, which will generate a report of your code base with percentage of complete coverage for each file. The green represents coverage and the red represents missing coverage. Depending on how many unit tests you've used while developing your project, this will reflect that commitment in the report.

One of the nice things with Scoverage is that it has integrations with Sonarqube (http://www.sonarqube.org/#), which is a “central place to manage code quality.” If you haven't used it before, it can be seen in the demo here: https://nemo.sonarqube.org/. Sonarqube is a really nice way to start getting visibility on your code coverage and a great way to show off just how much technical debt you've been able to crunch through.

SUMMARY

This chapter has covered many of the most popular styling/lint tooling to be used with Scala. These tools come from the open source world, and they of course increase the efficiency of your Scala applications and services. Be sure to try these tools, whether it is Scaliform, Scapegoat, WartRemover, or Scoverage, since they will make your Scala code easier to maintain.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset