Format things with scalafmt

Format things with scalafmt

9b888a029ae98abd2675b115ff0c4256?s=128

Rikito Taniguchi

November 10, 2018
Tweet

Transcript

  1. Format things with scalafmt Scala 関西 Summit 2018 @tanishiking

  2. こんにちは - Twitter: tanishiking - GitHub: tanishiking - Hatena: tanishiking24

    株式会社はてな(京都オフィス)で働いています。 Perl/TypeScript/Scala/Golang LinterやFormatterなどの開発支援ツールに興味があります。
  3. Agenda 1. コードフォーマッタを導入する利点 2. scalafmt の紹介 ◦ scalariform との違い /

    scalameta 3. scalafmt の使い方 4. Configuration ◦ とりあえずこの辺設定すればOKというものをいくつか紹介 します。
  4. Coding style どうしてる? - 特にルールはない - コードレビューでスタイルについて議論し てる? - チームにスタイルガイドがある?

    - フォーマッタをすでに導入している?
  5. 特にルールはない - 誰も気にしてないならそれはそれで良い - プロジェクトに人が増えるとカオスになるかも...? - 個々人が暗黙的なルールに従っている?

  6. コードレビューで何とかする レビュアーによって好みが違うかも スタイルに関する議論がレビューのたびに起こる - 「スペースよりタブを使うべきだ」 - 「この行長すぎるので適当なところで改行してほしいです」 - 「if の後にスペースがほしいです」

    - 「インデントの数がおかしそう」 - 「import の順番アルファベット順にしたくないですか?」 - 「=> を上の行の => と揃えてほしい」
  7. スタイルガイドを整備しても “any style guide written in English is either so

    brief that it’s ambiguous, or so long that no one reads it.” Bob Nystrom The Hardest Program I've Ever Written http://journal.stuffwithstuff.com/2015/09/08/the-hardest-program-ive-ever-written/
  8. エディタの設定を共有する? 人によって使っているエディタや IDEは違う!

  9. Code Formatter!! “Spend more time discussing important issues in code

    review and less time on code style. Scalafmt formats code so that it looks consistent between people on your team.” scalafmt.org
  10. scalafmt - scala(とsbt)のためのコードフォーマッター - scalaプログラムの解析にscalametaを利用 - 多機能! - プログラムの最大カラム数を指定できる(JSのprettierとか にもあるよね)

    - コメントとかのalignもできる!(gofmtとかもできるよね) - (両方あってすごい)
  11. scalariform or scalafmt - scalariform - 独自実装されたscalaのparserを利用 - 2.12のsyntaxには未対応 -

    scalafmt - scalametaというscalaのコードを解析するライブラリを利用 - 最新のscalaのsyntaxにも対応、Dottyにも対応予定 - maxColumn
  12. Install scalafmt - CLI - coursier - brew - SBT

    Plugin - sbt-scalafmt (こっちが公式) - neo-sbt-scalafmt - Editor/IDE plugin - IntelliJ plugin - vim-autofmt
  13. Install scalafmt (おすすめ) - CLI - coursier (coursier bootstrap で作ったlauncherをgit管理)

    - brew - SBT Plugin - sbt-scalafmt (こっちが公式) - neo-sbt-scalafmt - Editor/IDE plugin - IntelliJ plugin - vim-autofmt
  14. Configurations https://scalameta.org/scalafmt/docs/configuration.html - かなり多い。主要なものだけ紹介します。 - maxColumn - continuationIndent - align

    - RewriteRules - verticalMultiline - trailingCommas
  15. maxColumn (default: 80) // before class ExtendTest extends A with

    B with C with D // after (maxCoulumn=20) class ExtendTest extends A with B with C with D ※必ず指定した値以内に収まるわけではないことに注意
  16. continuationIndent インデントのスペース数に関する設定 - callSite (default: 2) - defnSite (default: 4)

    - extendsSite (default: 4)
  17. continuationIndent.callSite (default: 2) // before function( foo: Type, bar: Type

    ) // after function( foo: Type, bar: Type )
  18. continuationIndent.defnSite (default: 4) // before def function( foo: Type, bar:

    Type ) // after def function( foo: Type, bar: Type )
  19. continuationIndent.extendSite (default: 4) // before class UserProfile extends Profile with

    SomeTrait // after class UserProfile extends Profile with SomeTrait
  20. align 「=」「<-」「%%」「//」などを縦方向で揃える設定 - none - some (default) - more -

    most align.tokens で詳細を設定できるが、上記の4種類で十分
  21. align = none // before x match { case "foo"

    => 1 // comment case "hoge" => 123 // comment case "foobar" => 12345 // comment } // after x match { case "foo" => 1 // comment case "hoge" => 123 // comment case "foobar" => 12345 // comment }
  22. align = some (default) // before x match { case

    "foo" => 1 // comment case "hoge" => 123 // comment case "foobar" => 12345 // comment } // after (case match の => のみ align する) x match { case "foo" => 1 // comment case "hoge" => 123 // comment case "foobar" => 12345 // comment }
  23. align = more // before x match { case "foo"

    => 1 -> 1 // comment case "hoge" => 123 -> 123 // comment case "foobar" => 12345 -> 12345 // comment } // after (// や -> も) x match { case "foo" => 1 -> 1 // comment case "hoge" => 123 -> 123 // comment case "foobar" => 12345 -> 12345 // comment }
  24. align = more // before val foo = 1 val

    hoge = 2 libraryDependencies ++= Seq( "org.scala-lang" % "scala-compiler" % scalaVersion.value, "com.tanishiking" %% "scalaunfmt" % "0.0.1" ) // after (= や sbtの % も) val foo = 1 val hoge = 2 libraryDependencies ++= Seq( "org.scala-lang" % "scala-compiler" % scalaVersion.value, "com.tanishiking" %% "scalaunfmt" % "0.0.1" )
  25. align = most // before for { x <- List()

    yyy = 2 } yield { // ... } // after (<- と = をもalign) for { x <- List() yyy = 2 } yield { // ... }
  26. RewriteRules - AvoidInfix - RedundantBraces - RedundantParens - SortModifiers -

    SortImports 他にもいくつか...
  27. RewriteRules - AvoidInfix // before foo toList map { x

    => x should have length 5 } // after foo.toList.map { x => (x should have).length(5) }
  28. RewriteRules - RedundantBraces // before val x: Int => String

    = { case 2 => { "two" } case _ => { "other" } } // after val x: Int => String = { case 2 => "two" case _ => "other" }
  29. RewriteRules - RedundantParens // before for { a <- b

    if ((b ++ b).length >= 2) } yield a // after for { a <- b if (b ++ b).length >= 2 } yield a
  30. RewriteRules - SortModifiers // before final lazy private implicit val

    x = 42 lazy final implicit private val y = 42 // after implicit final private lazy val x = 42 implicit final private lazy val y = 42 sortModifiers.order = [“implicit”, “final” … ] で順番の設定も可能
  31. RewriteRules - SortImports // before import a.b.{c, a, b}, k.{

    g, f } // after import a.b.{a, b, c}, k.{f, g}
  32. verticalMultiline 1.6.0-RC1 からの機能 カラム数が `maxColumn` を超えたときのための設定 - newlineBeforeImplicitKW - newlineAfterImplicitKW

    - newlineAfterOpenParen
  33. newlineBeforeImplicitKW (default: false) // before override def load()(implicit taskCtx: Context,

    ec: ExecutionContext ): Future[Seq[A] Or B] // after override def load()( implicit taskCtx: Context, ec: ExecutionContext ): Future[Seq[A] Or B]
  34. newlineAfterImplicitKW (default: false) // before override def load()(implicit taskCtx: Context,

    ec: ExecutionContext ): Future[Seq[A] Or B] // after override def load()(implicit taskCtx: Context, ec: ExecutionContext ): Future[Seq[A] Or B]
  35. trailingCommas - 1.6.0-RC1 からの新機能 - 1.6.0-RC4時点ではまだ不安定、1.6.0 までお待ちを... - never -

    preserve (default) - always
  36. 結局どういう設定が良いのか 作者いわくおすすめはdefault 個人的には今日紹介した設定を好みに合わせて設定するのがオ ススメ

  37. diffをできるだけ少なくしたい? https://github.com/mikr/whatstyle $ python whatstyle.py --formatter scalafmt --ignoreopts IGNOREOPTS <scalafile>

    - diffの少ない設定を生成してくれる - 他のフォーマッタ(rustfmt, scalariform, clang-format な ど)にも対応 - フォーマッタ本体と独立している
  38. diffをできるだけ少なくしたい? https://github.com/tanishiking/scalaunfmt maxColumn = [80, 100] align = [some, more,

    most] continuationIndent.callSite = [2, 4] continuationIndent.defnSite = [2, 4] verticalMultiline.newlineAfterImplicitKW = [true, false] $ scalaunfmt --config .scalaunfmt.conf test1.scala test2.scala - 設定の候補を(ホワイトリスト形式で)選べる - JVM warmup によるボトルネックがなく高速(whatstyle比)
  39. scalafmt is not perfect - https://gitter.im/scalameta/scalafmt - https://github.com/scalameta/scalafmt/issues 質問はGitter、バグ報告はissueで

  40. まとめ - コードフォーマッタを導入することでstyleに関する議論や注意 を減らし、本質的な問題に注目できる。 - scalafmtの導入は - coursier bootstrap -

    sbt-scalafmt - おすすめ設定は基本default、好みで align, continuationIndent など - 質問はgitterまで!
  41. FAQ - JVM起動がボトルネックでscalafmtの起動が遅い - nailgun - SubstrateVM - githookでscalafmtしたい -

    https://medium.com/zyseme-technology/code-formatting-scalafmt-a nd-the-git-pre-commit-hook-3de71d099514 - sbtマルチプロジェクトで設定共有したい - common project で scalafmt.conf を生成するタスクを scalafmtConfigに依存させると吉 - コンパイル時にscalafmt走らせたい - scalafmtOnCompile (sbt-scalafmt)