このページでは、sbt 1.0のコーディングスタイルとその他のガイドラインについて説明します。
sbt 1.0は主にScala 2.12をターゲットとします。Scala 2.10とのクロスビルドも行います。
1.0リリース前に、非推奨事項をクリーンアップする必要があります。
Scala 2.12では、警告をゼロにすることを目指すべきです。クロスビルドに必要な場合、非推奨は例外となる可能性があります。
トレイト/クラスの実装を詳細に説明する前に、Scaladocから始めることは、その存在の必要性を考慮する必要があるため、しばしば役立ちます。
新しく導入されたすべての**公開**トレイトとクラス、そして程度は低いですが、関数とメソッドには、Scaladocが必要です。既存のsbtコードの多くはドキュメントが不足しており、時間をかけてこの状況を改善する必要があります。ドキュメントを追加したり、既存のドキュメントを改善する機会があれば、それも役立ちます。
パッケージレベルのドキュメントは、さまざまなコンポーネントがどのように相互作用するかを説明するのに最適な場所であるため、可能な限り追加/拡張することを検討してください。
優れたScaladocスタイルの詳細については、Scaladocスタイルガイドを参照してください。
ビルドユーザーに公開できるメソッドが少ないほど、sbtのメンテナンスが容易になります。
インターフェースに対してコードを作成します。
実装の詳細は、`sbt.internal.x`パッケージに隠す必要があります。ここで`x`はメインパッケージの名前(`io`など)です。
依存ライブラリが少ない独立したモジュールは、再利用が容易です。
標準的なScalaとJavaのクラスを除き、APIで外部クラスを公開することは避けてください。
公開用途がないモジュールは、内部モジュールとして宣言できます。
-encoding utf8
-deprecation
-feature
-unchecked
-Xlint
-language:higherKinds
-language:implicitConversions
-Xfuture
-Yinline-warnings
-Yno-adapted-args
-Ywarn-dead-code
-Ywarn-numeric-widen
-Ywarn-value-discard
-Xfatal-warnings
回避できない警告がある場合は、`-Xfatal-warnings`を削除できます。
IOレイヤーの場合は`sbt.io`など、パッケージ名にレイヤー名を付加して使用します。公開アーティファクトの組織名は`org.scala-sbt`のままにしてください。
バイナリ耐性に関する良い概要は、Joshの2012年の講演です。ここのガイドラインは、主に公開されているAPIに適用されます。
MiMaを使用してください。
To trait, or not to trait? 抽象クラスはトレイトほど柔軟ではありませんが、トレイトはバイナリ互換性に関してより多くの問題を引き起こします。抽象クラスは、Javaとの相互運用性も向上しています。
クラスを開いたままにする必要がない場合は、シールします。
クラスを開いたままにする必要がない場合は、ファイナライズします。
純粋なトレイトを使ったタイプリストパターンは、サブクラス化よりもバイナリ互換性の維持を容易にする可能性があります。
ケースクラスはコード生成に関与するため、時間の経過とともにバイナリ互換性を維持することが困難になります。
デフォルトのパラメータ値は事実上コード生成であり、維持が困難になります。
sbt公開APIに関するその他のガイドラインを以下に示します。
データ型を定義します。
`def apply`は、型`T`を返すコンパニオンオブジェクトのファクトリメソッドに予約する必要があります。
`scala.Seq`は`scala.collection.Seq`であり、不変ではありません。`Vector`をデフォルトとして使用します。定数プリペンドが必要な場合は`List`を使用します。Javaとの相互運用性が必要な場合は`Array`を使用します。可変コレクションをインプリメンテーション内で使用することは問題ありません。
`contains`や`subsetOf`のような集合演算に固執する場合は、`Set`で問題ありません。多くの場合、`toSeq`が明示的または暗黙的に呼び出されたり、`map`から副作用のあるメソッドが呼び出されたりします。これにより、コードに非決定性が導入されます。
上記と同じです。これにより非決定性が導入されます。
関数とタプルではなく、それらをトレイトに変換します。これは、インクリメンタルコンパイルの実装など、相互運用性が懸念される場合に適用されます。
sbt-houserulesには、ソースコードを一貫してフォーマットするためのscalafmtが含まれています。
明示的な`Unit`戻り値を宣言します。
このスタイルが推奨されます。
final class FooID {}
object FooID {
implicit val fooIdPicklerUnpicker: PicklerUnpickler[FooID] = ???
}
コンパニオンオブジェクトとパッケージオブジェクトに暗黙のコンバーターを定義することは避けてください。
IOモジュールがRichURI
というURL
のエンリッチメントを導入し、LibraryManagementがModuleID
構文用のGroupID
というString
のエンリッチメントを導入すると仮定します。これらの暗黙の変換は、それぞれのパッケージ内のsyntax
という名前のオブジェクトで定義する必要があります。
package sbt.io
object syntax {
implicit def uriToRichURI(uri: URI): RichURI = new RichURI(uri)
}
すべてのレイヤーが利用可能な場合、sbt
パッケージも、すべてのレイヤーからの暗黙の変換を転送するsyntax
という名前のオブジェクトを定義する必要があります。
package sbt
object syntax {
implicit def uriToRichURI(uri: URI): io.RichURI = io.syntax.uriToRichURI(uri)
....
}