CoffeeScriptの基礎まとめ その2
今回は文字列を扱います。
s = "hello" s = "this is a pen. this is a panda. this is the end"
ヒアドキュメントを使うと、こうなります。
s = "hello" s = """this is a pen. this is a panda. this is the end"""
変数を展開させるためには以下のようにします。
name = "zakiyama" alert "hi, #{name}"
数値計算もできます。
alert "hi, #{15/3}"
CoffeeScriptの基礎まとめ その1
家でアプリをつくるときにRails3.2を使っているのですが、そのRails3ではCoffeeScriptファイルが自動で生成されるようになっています。
もともと興味があったこともあって、せっかくの機会なので勉強してみようと思い、少し基礎をまとめてみました。
コメントアウト
# コメントアウト
### コメントアウト ###
JavaScriptとの違い
- varは不要
- 行末のセミコロン不要
- 波括弧はインデントで表現
- 丸括弧は曖昧性がない場合は省略可能
JavaScriptで書くとこうなる
var message = "hello world"; if (message.length > 1) { alert(message); }
これをCoffeeScriptで書くとこうなる
message = "hello world" if message.length > 1 alert message
javascriptの勉強 その3 -関数-
引き続き、javascriptの勉強をしていきます。
今回は少し重めの関数の話。
それでは早速。
- 関数は一連の命令文を内包したjavascriptの基本的な部品である
- 関数は、コードの再利用、情報の隠蔽、プログラムの構造化のために利用される
- また、関数はオブジェクトの振る舞いを規定するためにも利用される
- 一般的にプログラミングを行うということは、一連の要求仕様を関数とデータ構造に分解するための作業である
- Functionオブジェクト
- javascriptにおける関数はオブジェクトである
- オブジェクトは複数の名前と値のペアで構成されており、プロトタイプオブジェクトへの隠れたリンクをもっている
- FunctionオブジェクトはFunction.prototypeにリンクされている(そしてそれはObject.prototypeへリンクされている)
- すべての関数は、生成される際にさらにもう2つの隠されたプロパティを持つようになっている
- それは、その関数の振る舞いを決めるためのコンテキストとコードである
- 関数オブジェクトもすべて、生成時にprototypeプロパティが同時に生成される
- その値はオブジェクトであり、そのconstructorプロパティにはその関数自身がセットされている
- 関数はオブジェクトなので、それ以外の値と同様に扱うことができる
- 関数を変数やオブジェクト、配列に格納することもできる
- 関数が他のオブジェクトと異なるのは、それを呼び出すことができるという点である
- javascriptにおける関数はオブジェクトである
// addという変数を定義し、2つの値を加算する関数を格納する var add = function (a, b) { return a + b; }
- 関数リテラルつづき
- 関数リテラルは4つのパーツで構成される
- 1番目はfunctionという予約語
- 2番目は関数の名前で、これは省略可能
- 関数に名前をつけることで、再帰的に呼び出すことが可能となる
- 3番目は括弧で囲まれた関数のパラメータである
- 通常の変数がundefinedで初期化されるのと異なり、これらの変数はその関数が呼び出された際に、渡された引数で初期化される
- 4番目は中括弧で囲まれた、命令文の集合体である
- これらの命令文は関数の本体であり、その関数が呼び出された際に実行される
- 関数リテラルは、式を記述可能な場所であればどこにでも記述することができる
- 関数を他の関数の内部で定義することもできる
- 内包された関数は、もちろんそれ自身のパラメータや変数にアクセスできるが、それだけでなく、その関数を内包している外側の関数のパラメータや変数にアクセスすることもできる
- 関数リテラルで定義された関数オブジェクトは、外部コンテキストへのリンクも保持していると言える
- この機能は「クロージャ」と呼ばれ、これを活用することで、かなり高い表現力を得ることができる
- 関数リテラルは4つのパーツで構成される
- 関数の呼び出し
- 関数の呼び出しを行うと、現在実行されている関数の処理は一旦停止され、コントロールとパラメータが新しい関数へと渡される
- 定義されたパラメータに加えて、すべての関数はあと2つのパラメータを自動的に受け取っている
- それはthisとargumentsである
- thisパラメータはオブジェクト指向プログラミングにおいては非常に重要なもので、その値は呼び出しのパターンによって異なる
- javascriptの呼び出しのパターンは、メソッド呼び出しパターン、関数呼び出しパターン、コンストラクタ呼び出しパターン、apply呼び出しパターンの4つの種類があるが、これらの違いは、thisという追加パラメータがどのように初期化されるか、という点にある
- メソッド呼び出しパターン
- 関数がオブジェクトのプロパティとして格納されている場合には、メソッドと呼ばれる
- メソッドが呼び出された場合、thisにはそのオブジェクトが格納される
// myObjectを生成する // これはvalueプロパティとincrementメソッドをもつ // incrementメソッドはパラメータを1つとり、これは省略可能である // 引数が数値ではなかった場合、 // 代わりにデフォルト値として1が使われる var myObject = { value: 0, increment: function (inc) { this.value += typeof inc === 'number' ? inc : 1; } }; myObject.increment(); document.writeIn(myObject.value); // 1 myObject.increment(2); document.writeIn(myObject.value); // 3
- メソッド呼び出しパターンのつづき
- メソッドではthisを使ってオブジェクトにアクセスできるので、オブジェクトから値を取得したり、オブジェクトの内容を修正したりすることができる
- thisへのオブジェクトのセットは、呼び出しが発生したタイミングで行われる
- 遅延束縛と呼ばれるこの割り当てのタイミングのおかげで、thisは非常に便利なものとなっている
- thisを使って自分自身のオブジェクトコンテキストにアクセスしているメソッドは、パブリックメソッドと呼ばれる
- 関数呼び出しパターン
- 関数がオブジェクトのプロパティではない場合は、関数として呼び出される
- このパターンで呼び出された関数では、thisにはグローバルオブジェクトがセットされる。これは言語の設計としては失敗である。
- これには回避策が存在する。
- もしメソッド内で別の変数を定義し、その中にthisの値を代入すれば、内部関数ではその変数を通じてthisの値にアクセスできるようになる
var sum = add(3, 4); // sumは7
// myObjectにdoubleメソッドを追加する myObject.double = function() { var that = this; // 値の待避 var helper = function() { that.value = add(that.value, that.value); }; helper(); // helperを関数として呼び出す }; // doubleをメソッドとして呼び出す myObject.double(); document.writeIn(myObject.value);
- コンストラクタ呼び出しパターン
- javascriptは、プロトタイプ継承を行う言語である
- これは、オブジェクトが他のオブジェクトから直接継承を行うことを意味する
- そしてこの言語にはクラスの概念は存在しない
- もし関数を呼び出す際に、new演算子が前に付けられていた場合、新しいオブジェクトが生成されて、thisにはその新しいオブジェクトがセットされるようになる
- そしてそのオブジェクトは、呼び出された関数のprototypeプロパティへの隠されたリンクをもっている
- javascriptは、プロトタイプ継承を行う言語である
// Quoという名のコンストラクタ関数を生成する // これはstatusプロパティをもつオブジェクトを生成する var Quo = function (string) { this.status = string; }; // get_statusというパブリックメソッドを // Quoのすべてのインスタンスで利用可能にする Quo.prototype.get_status = function () { return this.status; }; // Quoのインスタンスを生成する var myQuo = new Quo("confused"); document.writeIn(myQuo.get_status()); // confused
- コンストラクタ呼び出しパターンつづき
- new演算子をつけて呼び出すことを前提とした関数は、コンストラクタと呼ばれる
- コンストラクタは、大文字で始まる名前の変数に格納されるのが慣例である
- new演算子をつけて呼び出すことを前提とした関数は、コンストラクタと呼ばれる
- apply呼び出しパターン
- javascriptは関数型オブジェクト指向言語であり、関数はメソッドをもつことがきる
- applyメソッドを使うことで、引数を格納した配列を使って関数を呼び出すことができる
- さらに、applyメソッドを使うことでthisにセットされている値を自由に設定することが可能になる
- applyメソッドには2つのパラメータを指定することができ、1つ目はthisにセットしたい値、2つ目はパラメータの配列である
// 2つの数値からなる配列を作り、それらを足し合わせる var array = [3, 4] var sum = add.apply(null, array); // sumは7 // statusというメンバをもつオブジェクトを生成する var statusObject = { status: 'A-OK' }; // statusObjectはQuo.prototypeを継承していない // しかし、statusObjectがget_statusメソッドを持っていないにも // かかわらず、statusObjectのget_statusメソッドを呼び出すことが可能になる var status = Quo.prototype.get_status.apply(statusObject); // statusは'A-OK'
- 変数型の拡張
- javascriptでは、標準で用意されている変数型を拡張することができる
- 以前、Object.prototypeを使うと、すべてのオブジェクトで利用できるメソッドを追加できることを紹介したが、関数や、配列、文字列、数値、正規表現、真偽値においても、同様のことが言える
- 標準で用意されている変数型を拡張することで、言語の表現力を飛躍的に高めることができる
- javascriptのプロトタイプ型のインターフェイスがもつ動的な性質のおかげで、メソッドを追加すると、その変数型の値すべてが即座にそのメソッドを利用できるようになる
- たとえば、Function.prototypeを拡張することで、すべての関数で利用できるメソッドを追加することができる
Function.prototype.method = function (name, func){ this.prototype[name] = func; return this; };
ひとまず今回はここまでにします。
長々とお付き合いいただきありがとうございます。
javascriptの勉強 その2 -オブジェクト-
引き続きjavascriptの勉強を進めていきます。
今回はオブジェクトの話です。
オブジェクト
- javascriptには、単純な変数型として、数値、文字列、真偽値(trueとfalse)、null、undefinedがある
- そして、それ以外の値はすべてオブジェクト
- 数値、文字列、真偽値はメソッドを呼び出すことができる、という意味ではオブジェクトに似ている
- しかし、これらの値はイミュータブル、すなわち一度セットしたら値を変更できない
- 一方、javascriptにおけるオブジェクトはキーによって整理されたミュータブル、つまり変更可能なデータの集合体
- javascriptでは、配列も、関数も、正規表現もすべてオブジェクト
- 当たり前だが、オブジェクトもオブジェクト
- オブジェクトは複数のプロパティをもつコンテナで、名前と値で構成されている
- プロパティ名は任意の文字列が利用でき、空文字も利用可能
- プロパティの値には、undefinedを除くすべてのjavascriptの値をセットできる
- javascriptにおけるオブジェクトはクラスの概念をもたない
- プロパティ名やプロパティの値に関して、何の制約ももたない
- オブジェクトはデータの集約や整理に非常に役立つ
- オブジェクトの中にオブジェクトを含むこともできるので、ツリー構造、グラフ構造を表すことも容易
- javascript には、他のオブジェクトのプロパティを継承することを可能にする、プロトタイプ連鎖の機能が用意されている
- これをうまく利用することで、オブジェクトの初期化のコストとメモリの消費量を抑えることができる
- オブジェクトリテラル
var empty_object = {}; var stooge = { "first-name": "Jerome", "last-name": "Howard" };
- オブジェクトリテラルつづき
- プロパティ名には、空文字を含む任意の文字列が利用できる
- プロパティ名の前後につけるクォート("")は、文字列が予約後ではなく、javascriptの名前に則っていれば、省略することができる
- たとえば、"first-name"の場合はクォートが必要だが、first_nameの場合には省略が可能
- プロパティの区切りにはカンマを利用する
- プロパティの値には任意の式を記述できるし、他のオブジェクトリテラルを含むことも可能(すなわち、オブジェクトはネストすることができる)
var flight = { airline: "Oceanic", number: 815, departure: { IATA: "SYD", time: "2004-09-22 14:55", city: "Sydney" }, arrival: { IATA: "LAX", time: "2004-09-23 10:42", city: "Los Angeles" } };
- 値の取得
- 文字列式を[]で囲んで指定することで、オブジェクトから値を取り出すことができる
- []の代わりに.を利用することもできる(ただし、文字列式が文字列リテラルで、予約語ではないjavascriptの名前のルールに則っている場合に限る)
- .を使った表現の方がおすすめ(コンパクトで読みやすいから)
stooge["first-name"] // "Jerome" flight.departure.IATA // "SYD"
存在しないメンバを取得しようとした場合にはundefinedが返される
stooge["middle-name"] // undefined flight.status // undefined stooge["FIRST-NAME"] // undefined
'||'演算子を使ってデフォルト値を設定することが出来る
var middle = stooge["middle-name"] || "(none)"; var status = flight.status || "unknown";
undefinedに対して、さらにそのプロパティを取得しようとしてしまうと、TypeError例外が投げられてしまう。
&&演算子を利用することでそうした事態を避ける事ができる
flight.equipment // undefined flight.equipment.model // "TypeError"が投げられる flight.equipment && flight.equioment.model // undefined
- 値の更新
- オブジェクトの値は、設定の場合と同様の方法で更新することができる
stooge['first-name'] = 'Jerome'
- プロトタイプ
- すべてのオブジェクトは、プロトタイプオブジェクトとリンクしていて、そこからプロパティを継承している
- オブジェクトリテラルによってつくられたオブジェクトはすべて、javascript標準のObject.prototypeオブジェクトとリンクしている
- オブジェクトを新たに生成する際には、プロトタイプとするオブジェクトを選択することができる
- Object関数にcreateメソッドを追加してみよう
- createメソッドは既存のオブジェクトをプロトタイプとして、新しいオブジェクトを生成する機能をもつ関数
- すべてのオブジェクトは、プロトタイプオブジェクトとリンクしていて、そこからプロパティを継承している
if (typeof Object.create !== 'function'){ Object.create = function (o) { var F = function () {}; F.prototype = o; return new F(); } }
- プロトタイプつづき
- プロトタイプとのリンクはオブジェクトの修正の際には何も影響を及ぼさない。つまり、オブジェクトの内容を書き換えた際に、プロトタイプの内容が変更されることはない。
- プロトタイプとのリンクは、オブジェクトから値を取得する際にのみ利用される
- オブジェクトから指定したプロパティの値を取得する際に、もしそのオブジェクト自身に指定された名前のプロパティがなかった場合、javascriptはプロトタイプオブジェクトからプロパティの値を取得しようとする
- そしてもしそこにもプロパティが存在しなかったら、さらにそのオブジェクトのプロトタイプにさかのぼっていき、最終的にObject.prototypeに行き着くまで検索が行われる
- もし該当するプロパティがプロトタイプチェーン上に存在していなかった場合には、undefinedという値が得られることになる
- この仕組みは「委譲」と呼ばれている
- プロトタイプの結びつきは、動的なものである
- プロトタイプオブジェクトに新しいプロトタイプを追加した場合、そのプロパティはその瞬間から、そのオブジェクトをプロトタイプとするオブジェクトすべてにおいてもアクセス可能になる
stooge.prefession = 'actor'; another_stooge.profession // 'actor'
- プロパティの削除
another_stooge.nickname // 'Moe' // another_stoogeからnicknameプロパティが削除され、 // プロトタイプ上のnicknameプロパティが見えるようになる delete another_stooge.nickname; another_stooge.nickname // 'Curly'
- グローバル領域の利用を減らす
- javascriptにおいて、グローバル変数を定義するのは簡単で、アプリケーションで利用するすべてのデータをそこに格納することができる
- しかしグローバル変数はプログラムの柔軟性を弱めてしまうので、使うべきではない
- 利用するグローバル変数を最低限にする方法の1つは、そのアプリケーションのためにグローバル変数を1つだけ定義することだ
javascriptの勉強 その1 -文法-
たまに少しかじったりはちょくちょくしてたけど、
じっくり勉強したことはなかったのでそろそろ時間をとってjavascriptを勉強してみる。
題材はO'REILLYの『Javascript : The Good Parts』。
O'REILLY大好きです。
javascriptの良い部分つまみ食いなので、少し違うところで勉強してから読んだほうがいいという所感。
目次
1章 良いパーツ 2章 文法 3章 オブジェクト 4章 関数 5章 継承 6章 配列 7章 正規表現 8章 メソッド 9章 スタイル 10章 美しい機能たち
文法
- 名前
- 予約語の多くは、javascriptの中では使われない
- undefined, NaN, Infinityなどは本来予約語になるべきなのになっていない
- 予約語は変数やパラメータの名前として利用することができない
- オブジェクトのプロパティとしても、オブジェクトリテラルとしても、ドットの後に書くようにしても使うことができない
- 予約語の多くは、javascriptの中では使われない
- 数値
- javascriptには数値型が1つしかない
- 他の言語と異なって、独立した整数型をもたない
- たとえば、1と1.0はまったく同じ値
- 数字を単に「数字」として認識すればいいので、数値型のせいで発生するエラーを気にする必要がない
- 数値はメソッドをもつ
- Mathオブジェクトが用意されている
- たとえば、Math.floorメソッドは数値を整数に変換する
- 文字列
- 命令文
- var文が関数内で使われたときは、その関数のプライベート関数を定義するものとなる
- switch, while, for, do文は、ラベルをオプションとして命令文の前に付けることができる
- そしてbreak文でそのラベルを指定することができる
- ブロックは一連の命令文のことで、中括弧で囲まれている
- ただし、javascriptのブロックは、他の言語と異なり、新しいスコープを生成しない
- そのため、変数はブロックの中でなく、関数の先頭で定義するべし
- for文は2種類の書き方をし、複雑なループを実行することができる
- 1つ目は初期化部分、条件式、増加部分という3つの省略可能な節を利用して制御を行う、昔から知られている書き方
- まず、初期化。ループ変数の初期化を行う。
- 次に、条件式が評価される。ループ変数がループを終了する条件を満たしたかどうかを調べる。
- 条件式が省略された場合、評価結果は常にtruly
- 評価式がfalsyと評価された場合、ループが終了
- もしループが終了されなければブロック部分が実行され、そして増加部分が実行されてから、条件式の評価の部分からループがくり返される。
- もう1つの書き方はfor inと呼ばれ、指定したオブジェクトのプロパティ名を列挙するものである
- この書き方では、それぞれのくり返しの際にオブジェクトのプロパティ名が1つずつ指定した変数に格納されていく
- その際には、object.hasOwnProperty(変数名)メソッドを利用して、そのプロパティ名が本当にそのオブジェクトのメンバか、それともプロトタイプチェーン上にあるものなのか、ということをチェックする必要がある場合が多い
for (myvar in obj) { if (obj.hasOwnProperty(myvar)){ ... } }
- 命令文のつづき
- try文はブロック部分を実行してその中で投げられたすべての例外をキャッチする
- catch節では、例外オブジェクトを受け取るために、新しい変数を定義する
- throw文は例外を発生させる
- そしてthrow文がtryブロック内に存在した場合は、catch節に処理が移る
- そうでなければ、その関数の実行は強制的に終了し、呼び出し元でtryが使われている場所のcatch節に処理が移動する
- throw文における式では通常、nameとmessageの2つのプロパティを含むオブジェクトリテラルを生成させる
- そうしておくことで、その例外をキャッチした際に何をすべきかを決定するための情報を得ることができる
- try文はブロック部分を実行してその中で投げられたすべての例外をキャッチする
- 関数
お読みいただきありがとうございます。
まだまだ続きますよ。
ruby script/runnerのお話
以前ruby script/runner関連で意味不明なエラーが出たのでちょっと調べてみました。
今の自分にはわからないことが多かったので、雑多にまとめてみようと思います。
「RailsアプリでActiveRecordを使ったバッチ処理 その2」
http://higelog.brassworks.jp/?p=12
- ruby on railsではscript/runnerを使えばWebアプリ内からではなくてもメソッドを実行することができる
- script/runnerはRails環境を読み込んだうえでワンライナーを実行するためのスクリプト
- このコマンドをcronなどで定期的に実行するようにする
「script/console と script/runner の環境の指定方法の違い」
http://d.hatena.ne.jp/takihiro/20080507/1210163583
script/console と script/runner で環境の指定の仕方が違うとのこと。
% ruby script/runner -e production % ruby script/console production
使い方のヘルプはそれぞれこんな感じ。
% ruby script/runner -h Usage: script/runner [options] ('Some.ruby(code)' or a filename) -e, --environment=name ...
% ruby script/console --help Usage: console [environment] [options]
環境を設定するコードも全然違うみたい。
- rails-2.3.14/lib/commands/runner.rb
require 'optparse' options = { :environment => (ENV['RAILS_ENV'] || "development").dup } code_or_file = nil ARGV.clone.options do |opts| opts.on("-e", "--environment=name", String, "Specifies the environment for the runner to operate under (test/development/production).", "Default: development") { |v| options[:environment] = v } end ENV["RAILS_ENV"] = options[:environment] RAILS_ENV.replace(options[:environment]) if defined?(RAILS_ENV)
- rails-2.3.14/lib/commands/console.rb
ENV['RAILS_ENV'] = case ARGV.first # (1) when "p": "production" when "d": "development" when "t": "test" else ARGV.first || ENV['RAILS_ENV'] || 'development' end
Rails task: script/runner or rake? - Stack Overflow
http://stackoverflow.com/questions/591503/rails-task-script-runner-or-rake
scrpt/runner some_useful_thing と rake some:other_useful_thingどちらが好まれるかという話。
script/runner がRailsを呼び出すのに対し、 rakeは :environment を指定したりして呼び出すことを明確にしない限りRailsを呼び出さない。
Railsを呼び出すのはコストがかかるので、避けられるに越したことはないという話になります。
とは言ってもほとんど同じとのこと。どちらも使うことはあるし、むしろ script/runner を使う人もいるようです。
script/runner OR script/rails runnerがクソ重い。どうしてくれんのよ?
http://d.hatena.ne.jp/babie/20100506/1273157249
Railsでのバッチ処理(script/runner)は環境を全部ロードするのでスタートアップがとても重いとのこと。
daemon_generatorなどを使う手もある。
他にもたくさん方法はあるみたいです。
- RailsアプリでActiveRecordを使ったバッチ処理 その3
http://higelog.brassworks.jp/?p=15
でもちょっと大げさ、というときのための手軽な方法があるようです。
actionに処理内容を書いて、ローカルのスクリプトからHTTPアクセスして叩く、という方法。
手動やcron/crontabで処理しようと思っていたなら使える方法です。
- app/controllers/hoge_controller.rb
class HogeController < ActionController::Base def batch # IP制限しないと怖いですよ…… raise NotFoundError.new unless request.remote_ip == "127.0.0.1" # 処理内容を書く ... render :text => "ok", :status => 200 end end
IPアドレスを制限するのがポイントとのこと。
じゃあバッチスクリプトはどう書くかというと、
- script/batch.rb
#!/usr/bin/env ruby require "net/http" Net::HTTP.version_1_2 if __FILE__ == $0 Net::HTTP.start('127.0.0.1', 80) do |http| response = http.get("/hoge/batch") unless response == Net::HTTPSuccess # log にエラーを吐くとか……適当に。 end end end
こんな感じで、cron/crontabに設定しておけばよいようです。
NotFoundErrorのところ、ちゃんと定義しておく必要がある(名前は任意)みたい。
- app/controllers/application_controller.rb
class ApplicationController < ActionController::Base ... class NotFoundError < StandardError; end rescue_from NotFoundError, :with => :record_not_found def record_not_found render :file => File.join(RAILS_ROOT, 'public', '404.html'), :status => 404 end end
すでにロードされているので激速とのこと。今度試してみる。
『良いコードを書く技術』のまとめ その1
そろそろリファクタリングとか良いコードを書くことをもっと意識してもいいなと思ったので、『良いコードを書く技術』を読んでみた。
いくつか参考になることがあったので、重要なところをまとめてみたいと思います。
目次
第1章 良いコードとは何か 第2章 良いコードを書くための5つの習慣 第3章 名前付け 第4章 スコープ 第5章 コードの役割 第6章 コードの集約 第7章 コードのパフォーマンス 第8章 ユニットテスト 第9章 抽象化 第10章 メタプログラミング 第11章 フレームワークを作ろう
良いコードの定義
本書では、次の4つを満たすものを良いコードと定義している。
- 保守性が高い
- すばやく効率的に動作する
- 正確に動作する
- 無駄な部分がない
良いコードを書くための習慣
長い期間プログラマをやっているからといって必ず良いコードが書けるようになるわけではない。
良いコードを書くための習慣を日々実践して、時間をかけて積み上げていくことが重要。
- その1 コードを読んで読んで読みまくる
- その2 とにかくコードを書く
- いったい何を書けばいいんだろうという人は、コードの写経をするとよい
- 写経することで、もとのコードが書かれた手順や、行間に潜む意図を伺い知ることができる
手の裏付けのない言葉はあまりに安い。人を動かしたかったら、まず自分の手を動かせ。手が塞がっていたら、手を動かした経験を語れ。口で語るな手で語れ。 ーー小飼弾「スーツの道も、舗装するのはギーク(404 Blog Not Found)2007」
- その3 道具を磨く
- コードを書くうえで必要な道具や環境を最高の状態に保つ
- 作業効率を上げていくことで、無駄のないプログラミングを行う
- その4 良い知識を得る
- 書籍を選ぶときは良書を選ぶべし
- 各言語において原典とも言える良書と、それを読みやすくするためのHOW TO本を組み合わせるとよいのでは
- その5 アウトプットと人からのFBでさらなる成長を
- コードレビューを受ける
- GitHubで自分のコードを公開する、公開されている他人のコードを読むことはおすすめ
- ブログを書く
- 勉強会に参加する
- コードレビューを受ける
名前付け
- 良い名前は重要
- 良い名前を使うことで読みやすく理解しやすいコードになり、保守性も向上する
- 逆に悪い名前はバグを生み出しやすく、保守が難しくなる
- 名前付けは良いコードの第一歩であり、基本中の基本
- オープンソフトウェアのコードを見たりして、命名の幅を広げるのも有効
- 名前付けがうまくできないときは設計を見なおしたほうがよいことが多い
- 良い名前の条件
- 変数名
- 変数名は宣言、代入、参照といった箇所でコード中に何度も登場するため、良い変数名を付けることができればコードの可読性は飛躍的に高まる
- 基本は説明的な名前を付ける
- 変数には値やオブジェクトが格納されている。変数名を見るだけで何がどのような役割として格納されているかが明確にわかるものが良い名前
- 変数はスコープによって求められる良い名前の性質が異なる
- スコープが長いとさまざまな箇所から参照され影響範囲が広いため、注意が必要
- メソッド名
- 良いメソッド名は、名前から機能が想像できる
- メソッドは処理を行うので、メソッド名は動詞または動詞+目的語になっていることが多い
- インスタンスメソッドは「Report.new」のようにオブジェクト名と組み合わせて呼び出されるので、組み合わされたときに重複なく意味が通り名前にする
- クラスメソッドとクラス名も同様
- よく使用されるメソッドは簡潔で短い名前が良いと言われる
- クラス名
- 変数名やメソッド名と比べてクラス名は単位が大きいため、適切で良い名前を付けることが重要
- 良いクラス名は、名前だけで何を行うクラスかがわかる
- クラス名がうまく思い浮かばないときは、自分が作ろうとしているクラスの役割が整理できていない
- 1つのクラスに複数の責務を押しこんでいたり、役割があいまいだったりしている可能性がある
- クラスの名前付け=設計である
- 筆者「自分が知らない表現・概念は、自分の中から生まれない」
- より上位の表現をものにするには、いろいろなコードや書籍を読んだり、実際にコードを書いて試すことが重要
- クラス名に対する成長の過程
- 変数名やメソッド名と比べてクラス名は単位が大きいため、適切で良い名前を付けることが重要
- まとめ
- 最初から良い名前付けをできる人はいない
- どういう名前が良いのかを慎重に検討し、適切な名前を決定するプロセスを繰り返していく
- 自分が知らないまったく新しい概念の名前が、突然ひらめくことはない
- コードリーディングやコードレビュー、誰かに相談するなどして、名前の引き出しを少しずつ増やしていくことでネーミングセンスを鍛える
やたら長くなりそうなので、一旦ここで区切りますー