著者アーカイブ 杉浦

著者:杉浦

読むのが早いソースコード

 ソースコードは早く理解されるコードであることが要求されます。早く理解されるためには、書かれている文字が何なのか読み取られるという方法があります。同じ動作を関数化することはよく使われる手法です。

function natcmp_name($a, $b) {
	if (empty($a['nickname']) || $a['nickname'] == "") {
		$a['nickname'] = $a['fullname'];
	}
	if (empty($b['nickname']) || $b['nickname'] == "") {
		$b['nickname'] = $b['fullname'];
	}
}

 これは連想配列aと連想配列bを比較する関数です。比較の方法はニックネームの自然な辞書順の比較、もしニックネームがなければ代わりにフルネームを使う、です。この関数はabならば>0を返します。自然な辞書順というのは主に数字に関連した部分です。単純な辞書順では一文字ずつ文字を読み取り、違いが出た時点で順序を決定します。この単純な辞書順において’1abc’という文字列は’10abc’という文字列よりも後に並びます。これは2文字目のaと0の比較で0の方が辞書順で前に来るのが適当であるためです。自然な辞書順において’1abc’という文字列は’10abc’という文字列よりも後に並びます。
 この関数を用いてある3人の名前の並び順を決定する。コードを書くと次の様になります。

function natcmp_name($a, $b) {
	if (empty($a['nickname']) || $a['nickname'] == "") {
		$a['nickname'] = $a['fullname'];
	}
	if (empty($b['nickname']) || $b['nickname'] == "") {
		$b['nickname'] = $b['fullname'];
	}
	strnatcmp($a["nickname"], $b["nickname"]);
}
natcmp_name($person[1],$parson[2]);
natcmp_name($person[2],$parson[3]);
natcmp_name($person[3],$parson[1]);

 3回の比較が12行程度で記述できました。これを関数抜きで記述した場合、次のようになります

if (empty($person[1]['nickname']) || $person[1]['nickname'] == "") {
	$person[1]['nickname'] = $person[1]['fullname'];
}
if (empty($person[2]['nickname']) || $person[2]['nickname'] == "") {
	$person[2]['nickname'] = $person[2]['fullname'];
}
strnatcmp($person[1]["nickname"], $person[2]["nickname"]);
if (empty($person[2]['nickname']) || $person[2]['nickname'] == "") {
	$person[2]['nickname'] = $person[2]['fullname'];
}
if (empty($person[3]['nickname']) || $person[3]['nickname'] == "") {
	$person[3]['nickname'] = $person[3]['fullname'];
}
strnatcmp($person[2]["nickname"], $person[3]["nickname"]);
if (empty($person[3]['nickname']) || $person[3]['nickname'] == "") {
	$person[3]['nickname'] = $person[3]['fullname'];
}
if (empty($person[1]['nickname']) || $person[1]['nickname'] == "") {
	$person[1]['nickname'] = $person[1]['fullname'];
}
strnatcmp($person[3]["nickname"], $person[1]["nickname"]);

 21行であり、比較回数が増えればもっともっと増えます。これに目を通すのは前の例より時間がかかります。さらに置換ミスやタイプミスによる想定外の動作に気づきにくいという問題もあります。
 もっとも、一番読むのが早いのは何も書かれていないコードです。上に並べたコードは比較をしましたが比較から何も返ってきません、データを参照して、操作しているだけです。最後のコードに至ってはデータを上書きで壊すバグの元ですらあります。再利用の可能性のある場合でもコメントアウト、再利用の可能性のない場合は完全に消去。読む必要のある部分は0行になります。

著者:杉浦

正規表現の(?:)

 (?:)は(?:)で括られたグループは後方参照されないという記号です。後方参照は便利ですが、()もそれ以上に便利で多用しがちです。()が増えるとどこに何が格納されるかわかりにくくなりとても面倒です。(?:)ですっきりする例を挙げます。

 <([a-z])(?:(\s[^>]+)?)>(.*)<\/\1>

 HTMLやXMLの様なタグに使えそうな正規表現です。使えそうというのは、この表現は記事を書いている時の思い付きであり、私自身使ってないからです。.*はバグの温床です。これを(?:)抜きで状態遷移図っぽく可視化すると
 
 (?:)を使って可視化すると

 となります。前者のgroup2はいらない感じがしますが、後者では見事に消えています。

著者:杉浦

導入の簡単なwebページテストツール、Selenium IDEの紹介

 Selenium IDEは使うまでの導入が非常に楽なwebページテストツールです。多量のテストコードを書くのは手間ですし、Chrome、Firefox限定ですが、アドオンを入れるだけ、自分の操作を記録してコードに起こしてくれると扱いが簡単です。この記事はfirefox版でのインストールと操作の記録、再生の操作説明になります。
 アドオンというだけでインストールはSelenium IDE – Firefox 向けアドオンのページに飛んで”firefoxへ追加”からアドオン追加をするだけです。追加が完了した場合、右上のアイコンが現れます。

 アイコンを押したら下図の画面が出ます。赤丸ボタンで操作を記録開始します。

 記録停止は同じ場所に現れる赤い四角ボタンです。下図は、シーポイントラボのホームページを開いて、chrome開発者ツ…という記事を開いて、画面下へスクロールして、本文をクリックした、という操作を記録した場合になります。記録の保存、読込もできます。

 操作はGUI上から記録抜きに記述できます。操作コードには任意のjavascriptコードを実行というものもあり、ブックマークレットの応用でそれなりに拡張できます。困ったことにSeleniumIDEはfirefoxがfirefox quantumになったあたりで一度サポートが途切れて生まれ変わってます。検索して出てくる情報が古いとあてにならないことが多々あります。

著者:杉浦

chrome開発者ツールによる要素に付与されたイベントの調査

 開発者ツールを開いて(F12キーによるショートカットかオプション→その他のツール)、下図の赤丸部、ElementsEventListenersと開けば対象の要素を参照した時に、その要素に付与されているイベントを特定して見ることが出来ます。

 またAncestors Allにチェックを入れると下図の様に今そのページに存在するイベント全てを見ることが出来ます。

 余談ですがfirefoxでは下図の様に要素にイベントがついている場合、要素の横にEVとマークがつき、そこから参照することになります。display:flexのような大本が知りたい対象も表記されます。ただchromeの様にタブを開くような画面にたどり着けませんでした。いいところどりのツールを得るにはいささか手間なようです。

著者:杉浦

読みやすいソースコード

 この記事を読むよりリーダブルコードを読んだ方がよほど良いと思います。Amazonで売っている電子版は見つかりませんでした。リーダブルコードはQiitaの記事でよく引用されたり技術書ランキング | テック・ブック・ランク”、5万部売れたり(技術書にしては多いです)でよく読まれています。
 O’Reilly Japan – リーダブルコード
 コードの記述は想定外の動作を起こさず、正しく動作する記述であることが最も重要視され、次いで理解しやすさ、時々実行速度が優先されます。実行速度が三番手なのは雑なコードでも要求に対して十分高速な時が少なからずあるからです。理解しやすいコードはそのコードを読む、未来の自分、共同開発者、ユーザの助けになります。未来の自分と書くと語弊がありますが、この未来というのはわりと短期です。一月もすれば読まない部分のコードの記憶は怪しくなります。
 理解しやすいコードに必要な条件に誤解が起きないというものがあります。誤解が起きない書き方というのは、接続詞である演算子や括弧を少なくして多重コードを避ける、変数名や関数名の意味を一意に決まる限定的な言葉にする、などの書き方です。
 読みにくい多重コードは三項演算子、関数呼び出しが特にそうです。

hoge = a?b?c:d:e
hoge = a?b?c:d?e:f:g?h:i
hoge = a(b(c,d(e()),f(g(h(),i))))

 二重だけでもちょっと躊躇います。下二つはもう大惨事です。
 変数名の意味を一意にすることの効果は、コードの理解に必要な文章量を少なくする効果でもあります。良い命名がされたコードはコードの一部を読むのみでプログラムが分かります。悪い命名というのは例えば、次のような命名です。

results = Database.all_objects.filter("year <= 2011") 

この results には何が含まれているだろうか?

  • 「year <= 2011」のオブジェクト
  • 「year <= 2011」ではないオブジェクト
  • Dustin Boswell (著), Trevor Foucher (著), 須藤 功平 (解説), 角 征典 (翻訳). リーダブルコード (P.30).
     このような場合、言葉の意味を考えるなり調べるなりしてより限定的な言葉を選ぶことで解決します。調べる時は類語や色々な人のコード中に頻出する名前を調べるといいです。この例の場合はfilterの代わりにselectやexcludeが推奨されます。

    著者:杉浦

    javascriptの比較演算子==、!=と===、!===

    ==、!=と===、!===は曖昧な比較と厳密な比較です。==、!=と===、!===を使い分ける事で以前書いた暗黙の型変換に悩まされない比較を行うことができます。
     javascriptは暗黙の型変換を行う言語です。暗黙の型変換とは、黙って値の型(文字列、整数、真偽値等)を変える、という動作です。この暗黙の型変換は便利な一方で予期せぬ挙動を引き起こすことがあります。例えば、次の関数を考えます。この関数が行いたいことは、引数の値を+1して返す、ということです。

    (inc = function(v){
    	return v+1;
    })();
    

     この関数は次の結果を引き起こします。

    a=inc(2);
    //aは3
    a=inc("2");
    //aは"21"
    

     javascriptは親切にも文字列型である引数に合わせて、数値として扱いたい1を文字列型に変換してくれました。この様に暗黙的な型変換をして欲しくない時があります。if文では次の様なコードが例に挙げられます。

    (hoge = function(msg){
    	if(msg == ""){
    		//msgが空なら返す
    		return;
    	}
    	//msgを使ったして欲しい処理
    })();
    

     javascriptは数値0を文字列””に暗黙的に変換します。そのためmsgに格納されている値が数値0の場合、動作はifの中に入り込み、msgを使ったして欲しい処理を行わずにhoge(msg)を抜け出すものになります。==、!=は比較の際に暗黙的な型変換を行う比較演算子なのに対し===、!==は比較の際に型変換をさせない比較演算子です。これを用いて次の様に記述した場合、msgに格納されている値が数値0であってもif文の中に入り込まずに、msgを使ったして欲しい処理を行います。

    (hoge = function(msg){
    	if(msg === ""){
    		//msgが空なら返す
    		return;
    	}
    	//msgを使ったして欲しい処理
    })();
    

     

    著者:杉浦

    呼び出し側を気にしない引数、デフォルト引数

     関数には引数がつきものです。ソースコード中のある関数を変更する際、関数中の引数を増やしたくなる時があります。しかしながら、単純な関数の引数部分の変更は関数の呼び出し側の変更も引き起こします。関数がどこで呼び出されているのか探すのは手間です。良い命名がされているならば複数ファイル中の文字列検索でどうにかなりますが、その様でないコードは少なくないです。目的が機能の追加であり、既存部分の機能が変わらないとなればなおさらやりたくないものです。そのような時に、この呼び出し側を気にしない引数であるデフォルト引数が役に立ちます。
     デフォルト引数の書き方は次です。

    void makecoffee(type = 'black'){/*処理*/}

    大体の言語は同じように引数欄に”引数名=引数のデフォルト値”と設定できます。デフォルト引数の動作は、呼び出された時に引数が足りない場合は引数に設定されたデフォルト値が代入されて動く、引数が足りている場合は呼び出し側の値が代入されて動く、といった具合です。これで引数が足りないという構文エラーを回避して、僅かな書き換えで引数を追加できます。余談ですがjavaはこのデフォルト引数機能がありません。私の触れた周りでは関数の追加で解決していることが多かったです。次の様に引数の数が異なる呼び出し用関数を追加するわけですね。

    void makecoffee(){makecoffee('black')}//0個の引数で呼び出される関数makecoffee()。固定された値を引数にしてmakecoffee(type)を呼び出す。
    void makecoffee(type){/*処理*/}//1個の引数で呼び出される関数makecoffee(type)。
    

     javaの様な同じ関数名を許容する言語の場合、この引数の異なる関数の追加は特に自然な感じで作れます。

    著者:杉浦

    javascriptの一時的な関数、即時関数

     javascriptには即時関数という機能があります。

    即時関数 (IIFE; Immediately Invoked Function Expressions) は、関数がブラウザーのコンパイラーに読み込まれた直後に呼び出される関数です。IIFE は、関数宣言の末尾に追加の括弧 “()” があるかどうかで識別できます。

     Function (関数) – 用語集 | MDNより引用。
     書き方は

    (function(){/*処理本文*/}(引数));
    (function(){/*処理本文*/})(引数);
    

    です。どちらでも問題ありません。即時関数と名付けられていますが、動作からは一時的な関数とも言えます。即時関数は

  • 関数のインスタンスを作る
  • その関数を実行する
  • その関数を捨てる(ステートメントの実行を終了したあとはもう参照しないので)
  • Bear Bibeault; John Resig. JavaScript Ninjaの極意 (Kindle の位置No.2730-2732). . Kindle 版. より引用。
    ということを行います。
     即時関数が用いられる主な目的はスコープの制御です。スコープは変数名の参照範囲のことです。変数名ごとにスコープが定められており、スコープの範囲内ならば変数を呼び出し、書き換えることができ、範囲外ならば呼び出せず、書き換えられないといった具合です。
     即時関数内で宣言された変数は宣言された即時関数内のみがスコープになります。このため、あるコードを即時変数として記述したならば既存のコードの変数名を考慮することなくそのコードを既存のコードに継ぎ足せます。特に即時関数に出番があるのは、任意のページに好き勝手スクリプトを追加する目的であるブックマークレットや変数名の衝突が容易に予想できる圧縮される予定のコードなんかです。

    著者:杉浦

    調和のとれた色のセットを出力してくれるAdobe Color CC

    カラーホイール | カラースキーム – Adobe Color CC
    “Adobe Kuler の使用方法”
     Adobe Color CCは調和のとれた色のセットを出力してくれるwebアプリです。画面上のカラーホイール中のルーペをぐりぐり動かせば、他のルーペも連動して動いて、調和を維持したまま様々な色のセットを出力してくれます。Colorハーモニーが調和の種類の変更です。モノクロからきれいな多色まで様々です。

     画像の読み込みでは画像からは、その画像に沿った色のセットを読み込んでくれます。

     探索からは多数のユーザが作成した色のセットを探せます。

    著者:杉浦

    CSSの適用優先度

     CSSはHTMLに装飾を付ける仕組みで、主にその詳細度から適用の優先順位が決まります。要素名、クラス、ID、HTML中の直書きと適用される範囲が狭く詳細になるほど優先されます。定義はSelectors Level 3でされていますが、ご存知、ないのですか?CSSの優先順位の説明が大変分かりやすかったです。
     次の図は”ご存知、ないのですか?CSSの優先順位”からの引用です。


     図の様に指定方法の種類別総和が優先度になっています。この優先度の特徴として、IDの様なより詳細な種類の指定方法が用いられていた場合、どれだけクラスの様なより詳細でない種類の指定方法を重ね掛けても優先度で上回れないという点があります。優先度が同値の場合、後から読み込まれた方が優先されます。
     生のCSSではこの優先度を表記してくれません。人間がこの優先度を理解しながらCSSを読み解くのは難しいです。Specificity Calculatorは優先度計算ページです。下図の様に、CSSコードを書きこめば優先度を出力してくれます。計算機を増やしたいならば、Duplicateボタンで複製しましょう。