From 4dd6cc7ca3f2d8de55ea0bfca77ce8ca8dc3e163 Mon Sep 17 00:00:00 2001 From: okapies Date: Mon, 12 Mar 2012 01:45:16 +0900 Subject: [PATCH] closed #6: standardize technical terms. --- effectivescala-ja.mo | 150 ++++++++++++++++++++++--------------------- 1 file changed, 77 insertions(+), 73 deletions(-) diff --git a/effectivescala-ja.mo b/effectivescala-ja.mo index bb9c4bb..46ca150 100644 --- a/effectivescala-ja.mo +++ b/effectivescala-ja.mo @@ -29,11 +29,11 @@ Scalaは、簡潔な表現を可能にする数多くのツールを提供して では、楽しんでほしい。 -## 整形 +## 書式 -コード*整形*の詳細は、(それが実際的である限りは)重要じゃない。当然だが、スタイルに本質的な良し悪しはないし、たいていは人それぞれの個人的嗜好は異なる。だけど、同じ整形ルールを*一貫して*適用することは、ほぼ全ての場合で可読性を高める。特定のスタイルに馴染んだ読み手は、さらに他のローカルな習慣を理解したり、言語文法の隅っこを解読したりする必要がない。 +コードの*書式*の詳細は(それが実際的である限りは)重要じゃない。当然だが、スタイルに本質的な良し悪しはないし、たいてい人それぞれの個人的嗜好は異なる。しかし、同じ整形ルールを*一貫して*適用することは、ほぼ全ての場合で可読性を高める。特定のスタイルに馴染んだ読み手は、さらに他のローカルな慣習を理解したり、言語の文法の隅を解読したりする必要がない。 -これは文法の重複度が高いScalaにおいては特に重要だ。メソッド呼び出しを例に挙げよう。メソッドは、"`.`"を付けても、ホワイトスペースを付けても呼び出せる。同様に、ゼロまたは一つの引数を取るメソッドでは丸カッコを付けても良いし、付けなくても良い、といった風に。さらに、異なるスタイルのメソッド呼び出しは、異なる文法上の曖昧さを露呈する! 注意深く選ばれた整形ルールを一貫して適用することで、人間と機械の両方にとって、多くの曖昧さを解決できるのは間違いない。 +これは文法の重複度が高いScalaにおいては特に重要だ。メソッド呼び出しを例に挙げよう。メソッドは、"`.`"を付けても、ホワイトスペースを付けても呼び出せる。同様に、ゼロまたは一つの引数を取るメソッドでは丸カッコを付けても良いし、付けなくても良い、といった風に。さらに、様々なスタイルのメソッド呼び出しは、様々な文法上の曖昧さを露呈する! 注意深く選ばれた整形ルールを一貫して適用することで、人間と機械の両方にとって、多くの曖昧さを解決できるのは間違いない。 我々は、[Scala style guide](http://docs.scala-lang.org/style/)を遵守すると同時に、以下に示すルールを追加した。 @@ -45,29 +45,29 @@ Scalaは、簡潔な表現を可能にする数多くのツールを提供して
小さなスコープでは、短い名前を使う
-
ijkは、ループ内ではほとんど期待される。
+
ループでは、基本的にijkを使おう。
より大きなスコープでは、より長い名前を使う
-
外部APIには、より長く意味のある説明的な名前を付けるべきだ。Future.allではなくFuture.collectのような。 +
外部APIには、より長くて意味付けのできる説明的な名前を付けるべきだ。Future.allではなく、Future.collectのように。
一般的な略語を使い、難解な略語を避ける
-
誰でもokerrdefnが何を指すか知っている。一方で、sfriはそれほど一般的じゃない。
-
用法が異なるのに名前を再利用しない
+
誰でもokerrdefnが何を指すか知っている。一方で、sfriはそれほど一般的ではない。
+
異なる用途に名前を再利用しない
valを使おう。
予約名を ` を使ってオーバーロードするのは避ける
`type`の代わりに、typとする。
-
副作用を伴う操作には動作を表す名前を付ける(訳注:能動態?)
+
副作用を伴う操作には能動態で名前を付ける
user.setActive()ではなく、user.activate()とする。
値を返すメソッドの名前は説明的に
src.definedではなく、src.isDefinedとする。
getterの接頭にgetを付けない
-
以前のルールの通り、これは冗長だ。site.getCountではなく、site.countとする。
+
上にも書いた通り、これは冗長だ。site.getCountではなく、site.countとする。
パッケージやオブジェクト内で既にカプセル化されている名前を繰り返さない
object User {
   def getUser(id: Int): Option[User]
 }
よりも、
object User {
   def get(id: Int): Option[User]
-}
とする。User.getに比べて、User.getUserは何も情報を提供しないし、使うときに冗長だ。 +}とする。User.getと比べてUser.getUserは冗長だし、何も情報を与えない。
@@ -75,15 +75,15 @@ Scalaは、簡潔な表現を可能にする数多くのツールを提供して ### インポート
-
インポート行はアルファベット順にソートする
-
こうすることで、視覚的に調べやすいし自動化もしやすい。
+
インポート(import)行はアルファベット順にソートする
+
このようにすると、目で調べやすいし自動化もしやすい。
同じパッケージから複数の名前をインポートするときは中カッコを使う
import com.twitter.concurrent.{Broker, Offer}
-
6つより多くの名前をインポートするときはワイルドカードを使う
+
6個より多くの名前をインポートするときはワイルドカードを使う
e.g.: import com.twitter.concurrent._ -
ワイルドカードを濫用しないこと。一部のパッケージは、大量の名前をエクスポートしている。
+
ワイルドカードを濫用しないこと。一部のパッケージは、大量の名前をエクスポートする。
コレクションを使う時は、scala.collections.immutable あるいは scala.collections.mutable をインポートして名前を修飾する
-
可変(mutable)および不変(immutable)コレクションは、二重に名前を持っている。読み手のために、名前を修飾してどちらのコレクションを使っているのか明らかにしよう。 (e.g. "immutable.Map")
+
可変(mutable)コレクションと不変(immutable)コレクションは同じ名前を二重に使っている。読み手のために、名前を修飾してどちらのコレクションを使っているか明確にしよう。 (e.g. "immutable.Map")
他のパッケージからの相対指定でインポートしない
import com.twitter
 import concurrent
のようには書かず、以下のように曖昧さの無い書き方をしよう。
import com.twitter.concurrent
@@ -93,21 +93,21 @@ import concurrentのようには書かず、以下のように曖 ### 中カッコ -中カッコは、複合式を作るのに使われる("モジュール言語"では他の用途にも使われる)。そして、複合式の値は、リスト中の最後の式となる。単純な式に中カッコを使うのは避けよう。例えば、 +中カッコは、複合式を作るのに使われる("モジュール言語"では他の用途にも使われる)。複合式の値は、リスト中の最後の式となる。単純な式に中カッコを使うのは避けよう。例えば、 def square(x: Int) = x*x -.LP と書く代わりに、構文的にメソッドの本体を見分けやすい +.LP と書く代わりに、メソッドの本文を構文的に見分けやすい def square(x: Int) = { x * x } -.LP と書きたいと思うかもしれない。しかし、最初の記法の方が、乱雑さが少なく読みやすい。明確にするのが目的でないなら、構文的な儀礼は避けよう。 +.LP と書きたくなるかもしれない。しかし、最初の記法の方がゴチャゴチャしておらず読みやすい。明確化が目的でないなら仰々しい構文を使うのは避けよう。 ### パターンマッチ -適用できる場合は、関数定義の中ではパターンマッチを直接使おう。 +関数の定義でパターンマッチを直接使える場合は、いつでもそうしよう。 list map { item => item match { @@ -116,48 +116,48 @@ import concurrentのようには書かず、以下のように曖 } } -.LP とする代わりに、matchを折り畳んで +.LP という間接的な書き方は意図が明瞭でない。代わりにmatchを折り畳んで list map { case Some(x) => x case None => default } -.LP と書くと、リストの要素がmapされることが分かりやすい — the extra indirection does not elucidate. (←?) +.LP と書くと、リストの要素を写像(map over)しているのが分かりやすい。 ### コメント -[ScalaDoc](https://wiki.scala-lang.org/display/SW/Scaladoc)を使ってAPIドキュメントを提供しよう。以下のように書く: +[ScalaDoc](https://wiki.scala-lang.org/display/SW/Scaladoc)を使ってAPIドキュメントを提供しよう。以下のスタイルで書こう: /** * ServiceBuilder builds services * ... */ -.LP でも標準のScalaDocスタイルは使わないように: +.LP でも、標準のScalaDocスタイルは使わない方がいい: /** ServiceBuilder builds services * ... */ -アスキーアートや視覚的な装飾に頼ってはいけない。また、APIではない不必要なコメントをドキュメント化してはいけない。もし、自分のコードの挙動を説明するためにコメントを追加しているのに気づいたら、まずは、それが何をするコードなのか明白になるよう書き直せないか考え直してみよう。「見るからに、それは動作する (it works, obviously)」よりも「明らかにそれは動作する(obviously it works)」方が良い(ホーアには申し訳ないけど)。 +アスキーアートや視覚的な装飾に頼ってはいけない。また、APIではない不必要なコメントをドキュメント化してはいけない。もし、自分のコードの挙動を説明するためにコメントを追加しているのに気づいたら、まずは、それが何をするコードなのか明白になるよう書き直せないか考え直してみよう。「見るからに、それは動作する (it works, obviously)」よりも「明らかにそれは動作する(obviously it works)」方がいい(ホーアには申し訳ないけど)。 -(訳注: [アントニー・ホーア](http://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%B3%E3%83%88%E3%83%8B%E3%83%BC%E3%83%BB%E3%83%9B%E3%83%BC%E3%82%A2)は、自身のチューリング賞受賞講演の中で、*『極めて複雑に設計して「明らかな」欠陥を無くすより、非常に簡素に設計して「明らかに」欠陥が無いようにする方が遥かに難しい』*という趣旨の発言をしている。「コードから実装の意図を一目瞭然に読み取れるようにせよ」という主張は、上記のホーアの主張の真逆を言っている、ということだろう。) +(訳注: [アントニー・ホーア](http://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%B3%E3%83%88%E3%83%8B%E3%83%BC%E3%83%BB%E3%83%9B%E3%83%BC%E3%82%A2)は、自身のチューリング賞受賞講演で*『極めて複雑に設計して「明らかな」欠陥を無くすより、非常に簡素に設計して「明らかに」欠陥が無いようにする方が遥かに難しい』*という趣旨の発言をしている。一方、著者は「コードから実装の意図を一目瞭然に読み取れるようにせよ」という立場であり、つまりホーアとは真逆の主張をしていると言える。) ## 型とジェネリクス -型システムの主な目的は、プログラミングの誤りを検出することだ。型システムは、限定的な方式の静的検査を効果的に提供する。これにより、コンパイラが検証可能なコードにおいて、ある種の不変条件を表現できる。型システムがもたらす恩恵はもちろん他にもあるが、エラーチェックこそ、その存在理由(レーゾンデートル)だ。 +型システム(type system)の主な目的は、プログラミングの誤りを検出することだ。型システムは、制限された形態の静的検査を効果的に提供する。これにより、コードにおいてある種の不変条件(invariant)を記述でき、それをコンパイラで検証できる。型システムがもたらす恩恵はもちろん他にもあるが、エラーチェックこそ、その存在理由(レーゾンデートル)だ。 -我々が型システムを使う場合はこの目的を踏まえるべきだが、一方で、読み手にも気を配り続けなきゃいけない。型を慎重に使ったコードは明瞭さが高まるが、過剰に巧妙に使ったコードは読みにくいだけだ。 +我々が型システムを使う場合はこの目的を踏まえるべきだが、一方で、読み手にも気を配り続ける必要がある。型を慎重に使ったコードは明瞭さが高まるが、過剰に巧妙に使ったコードは読みにくいだけだ。 Scalaの強力な型システムは、学術的な探求と演習においてよく題材とされる(eg. [Type level programming in Scala](http://apocalisp.wordpress.com/2010/06/08/type-level-programming-in-scala/))。これらのテクニックは学術的に興味深いトピックだが、プロダクションコードでの応用において有用であることは稀だ。避けるべきだろう。 ### 戻り型アノテーション -Scalaでは戻り型アノテーション(return type annotation)を省略できるが、一方でそれらは良いドキュメンテーションであり、publicメソッドでは特に重要だ。露出していないメソッドで、戻り型が明白な場合は省略しよう。 +Scalaでは戻り型アノテーション(return type annotation)を省略できるが、一方で、アノテーションは優れたドキュメンテーションを提供する。戻り型アノテーションは、publicメソッドでは特に重要だ。露出していないメソッドで、かつ戻り型が明白な場合は省略しよう。 -これは、Scalaコンパイラが生成するシングルトン型をミックスインするオブジェクトをインスタンス化する場合は特に重要だ。例えば、`make` 関数が: +これは、ミックスインを使ったオブジェクトをインスタンス化する際に、Scalaコンパイラがシングルトン型を生成する場合は特に重要だ。例えば、`make` 関数が: trait Service def make() = new Service { @@ -168,15 +168,15 @@ Scalaでは戻り型アノテーション(return type annotation)を省略でき def make(): Service = new Service{} -`make` の公開型を変更することなく、さらに好きなだけtraitをミックスできるから、後方互換性の管理が容易になる。 +`make` の公開する型を変更することなく、traitをさらに好きなだけミックスできる。つまり、後方互換性の管理が容易になる。 ### 変位 -変位(variance)は、ジェネリクスが派生型と結びつく時に現れる。変位は、*コンテナ型*の派生型と、コンテナ型に*含まれる型*の派生型がどう関連するかを定義する。Scalaでは変位アノテーションを宣言できるから、コレクションに代表される共通ライブラリの作者は、多数のアノテーションを扱う必要がある。変位アノテーションは、共用コードの使い勝手を高める上で重要だが、誤用すると危険なものとなりうる。 +変位(variance)は、ジェネリクスが派生型(subtyping)と結びつく時に現れる。変位は、コンテナ型(*container* type)の派生型と、要素型(*contained* type)の派生型がどう関連するかを定義する。Scalaでは変位アノテーションを宣言できるから、コレクションに代表される共通ライブラリの作者は、多数のアノテーションを扱う必要がある。変位アノテーションは、共用コードの使い勝手を高める上で重要だが、誤用すると危険なものとなりうる。 -変位は、Scalaの型システムにおいて、高度だが必須の特徴だ。変位は、派生型の適用を助けるものとして、大いに(そして正しく)使われるべきだ。 +不変(invariant)は、Scalaの型システムにおいて高度だが必須の特徴だ。派生型の適用を助けるために、大いに(そして正しく)使うべきだ。 -*不変コレクションは共変であるべきだ*。要素型を受け取るメソッドは、コレクションを適切に"格下げ"すべきだ: +*不変コレクションは共変(covariant)であるべきだ*。要素型を受け取るメソッドは、コレクションを適切に"格下げ"すべきだ: trait Collection[+T] { def add[U >: T](other: U): Collection[U] @@ -231,7 +231,7 @@ Scalaでは戻り型アノテーション(return type annotation)を省略でき .LP は、意思疎通が目的で、簡潔さを高めたい場合に有用だ。 -エイリアスが使える場合は、サブクラスを使ってはいけない。 +エイリアスが使える場合はサブクラス化を使ってはいけない。 trait SocketFactory extends (SocketAddress) => Socket @@ -239,45 +239,45 @@ Scalaでは戻り型アノテーション(return type annotation)を省略でき type SocketFactory = SocketAddress => Socket -.LP を使う方がいい。今や、SocketFactory型の値のための関数リテラルが与えられているので、関数合成を使うことができる: +.LP を使う方がいい。これで、SocketFactory型の値となる関数リテラルを定義できるので、関数合成が使える: val addrToInet: SocketAddress => Long val inetToSocket: Long => Socket val factory: SocketFactory = addrToInet andThen inetToSocket -パッケージオブジェクトを使うと、型エイリアスをトップレベル名に結びつけられる: +パッケージオブジェクトを使うと、型エイリアスをトップレベル名に結びつけることができる: package com.twitter package object net { type SocketFactory = (SocketAddress) => Socket } -なお、型エイリアスは、型に対する別名の構文的な代わりとなるものであり、新しい型ではないことに留意しよう。 +なお、型エイリアスは、その型のエイリアス名を構文的に置換することと同等で、新しい型ではないことに留意しよう。 ### 暗黙 暗黙(implicit)は、型システムの強力な機能だが、慎重に使うべきだ。それらの解決ルールは複雑で、シンプルな字句検査においてさえ、実際に何が起きているか把握するのを困難にする。暗黙を間違いなく使ってもいいのは、以下の場面だ: * Scalaスタイルのコレクションを拡張したり、追加したりするとき -* オブジェクトを適合(adapt)させたり、拡張したりするとき("pimp my library"パターン) +* オブジェクトを適合(adapt)させたり、拡張(extend)したりするとき("pimp my library"パターン) * [制約エビデンス](http://www.ne.jp/asahi/hishidama/home/tech/scala/generics.html#h_generalized_type_constraints)を提供することで、*型安全を強化*するために使うとき * 型エビデンス(型クラス)を提供するため * `Manifest`のため 暗黙を使う場合は、暗黙を使わずに同じことを達成する方法がないか、常に確認しよう。 -似通ったデータ型同士を、自動的に変換するのに暗黙を使うのはやめよう(例えば、リストをストリームに変換する等)。型はそれぞれ異なった動作をするので、暗黙に型が変換されていないか、読み手に気を使わせることになる。明示的に変換するべきだ。 +似通ったデータ型同士を、自動的に変換するのに暗黙を使うのはやめよう(例えば、リストをストリームに変換する等)。それらの型はそれぞれ異なった動作をするので、読み手は暗黙の型変換が働いていないか注意しなくてはならなくなる。明示的に変換するべきだ。 ## コレクション -Scalaが持つコレクションライブラリは、非常に総称的で、機能豊富で、強力で、組み合わせが容易だ。コレクションは高水準であり、多数の操作を提供している。多数のコレクション操作と変換を簡潔かつ読みやすく表現できるが、それらの機能を不注意に適用すると、しばしば正反対の結果を招く。全てのScalaプログラマは、[collections design document](http://www.scala-lang.org/docu/files/collections-api/collections.html)を読むべきだ。このドキュメントは、Scalaのコレクションライブラリに対する優れた洞察と意欲をもたらしてくれる。 +Scalaが持つコレクションライブラリは、とても総称的(generic)で、機能豊富で、強力で、組み立てやすい。コレクションは高水準であり、多数の操作を提供している。多数のコレクション操作と変換を簡潔かつ読みやすく表現できるが、それらの機能を不注意に適用すると、しばしば正反対の結果を招く。全てのScalaプログラマは、[collections design document](http://www.scala-lang.org/docu/files/collections-api/collections.html)を読むべきだ。このドキュメントは、Scalaのコレクションライブラリに対する優れた洞察と意欲をもたらしてくれる。 常に、君のニーズを最もシンプルに満たすコレクションを使おう。 ### 階層 -コレクションライブラリは巨大だ。`Traversable[T]`を基底とする精密な階層に加えて、ほとんどのコレクションに`immutable`と`mutable`のバリエーションがある。複雑さはともかく、以下の図は、`immutable`と`mutable`の双方の階層にとって重要な区別を含んでいる。 +Scalaのコレクションライブラリは巨大だ。`Traversable[T]`を基底とする精密な階層に加えて、ほとんどのコレクションに`immutable`と`mutable`のバリエーションがある。どんなに複雑でも、以下の図は、`immutable`と`mutable`の双方の階層にとって重要な区別を含んでいる。 .cmd @@ -302,11 +302,11 @@ arrow from Iterable.s to Map.nw EOF .endcmd -.LP Iterable[T]はイテレートできるコレクションで、iterator(とforeach)メソッドを提供する。Seq[T]順序付けされたコレクション、Set[T]は数学的集合(要素が一意な順序の無いコレクション)、そしてMap[T]は順序の無い連想配列だ。 +.LP Iterable[T]はイテレート(iterate)できるコレクションで、iterator(とforeach)メソッドを提供する。Seq[T]順序付けされたコレクション。Set[T]は数学的集合(要素が一意な順序の無いコレクション)。そして、Map[T]は順序の無い連想配列だ。 -### 利用 +### 使う -*不変(immutable)コレクションを利用する。*不変コレクションは、ほとんどの状況に適用できると同時に参照透過なので、プログラムがデフォルトでスレッドセーフであると判断しやすくなる。 +*不変(immutable)コレクションを使おう。*不変コレクションは、ほとんどの状況に適用できる。また、プログラムが参照透過であり、故にデフォルトでスレッドセーフであると判断しやすくなる。 *`mutable`名前空間は明示的に使う。*`scala.collections.mutable._`をインポートして`Set`を参照する代わりに、 @@ -315,15 +315,15 @@ EOF .LP とすることで、可変な`Set`を使っていることが分かりやすくなる。 -*コレクション型のデフォルトコンストラクタを使う。*例えば、順序付きの(かつ連結リストの動作が必要ない)シーケンスが欲しい場合は、いつでも`Seq()`コンストラクタを使おう: +*コレクション型のデフォルトコンストラクタを使おう。*例えば、順序付きの(かつ連結リストの動作が必要ない)シーケンスが欲しい場合は、いつでも`Seq()`コンストラクタを使おう: val seq = Seq(1, 2, 3) val set = Set(1, 2, 3) val map = Map(1 -> "one", 2 -> "two", 3 -> "three") -.LP このスタイルでは、コレクションの動作がその実装と切り離されているので、コレクションライブラリは最も適切な実装型を使うことができる。君が必要としているのはMapであって、必ずしも赤黒木じゃない。さらに、これらのデフォルトコンストラクタは、しばしば特殊化した表現を用いる。例えばMap()は、3つのキーを持つマップに対して、3つのフィールドを持つオブジェクト(Map3クラス)を使う。 +.LP このスタイルでは、コレクションの動作がその実装と切り離されているので、コレクションライブラリは最も適切な実装型を使うことができる。君が必要としているのはMapであって、必ずしも赤黒木じゃない。さらに、これらのデフォルトコンストラクタは、しばしば特殊化された表現を用いる。例えばMap()は、3つのキーを持つマップに対して、3つのフィールドを持つオブジェクト(Map3クラス)を使う。 -以上からの結論として、メソッドやコンストラクタでは、*最も総称的なコレクション型を適切に受け取ろう*。これは詰まるところ、通常は上記の`Iterable`、`Seq`、`Set`あるいは`Map`のうち、どれか一つである。もしメソッドがシーケンスを必要とする場合は、`List[T]`ではなく`Seq[T]`を使おう。 +以上からの結論として、メソッドやコンストラクタでは、*最も総称的なコレクション型を適切に受け取ろう*。要するに、通常は上記の`Iterable`、`Seq`、`Set`あるいは`Map`のうち、どれか一つだ。もしメソッドがシーケンスを必要とする場合は、`List[T]`ではなく`Seq[T]`を使おう。