はてなキーワード: シグネチャとは
頼むからセンスのない奴はプログラマにならないでくれ。迷惑だから。
これが最もプログラマになってはいけないタイプ(犯罪行為などの言うまでもないことを除けば)。
たとえば
等。
不要なものを作ることで、プログラムは複雑になり、メンテナンスの手間は増え、バグは発生しやすくなる。
一定レベル以上のプログラマが最も自然だと同意するような実装(「実装しない」という選択肢もふくめて)をパッと思い付けない奴は、センスが足りていない。
将棋で言えば、駒がぶつかったら先ず取る手を考えるといった基本的な手筋が思い浮かばないようなもので、現実的に使い物にならない。
これは、「Code Complete」「The Pragmatic Programmer」等の著名なプログラミングの本に共通する結論である。
これが「The Pragmatic Programmer」にあるDRYの原則である。
要するに、すべての情報が単一のソースから決定されるべきということだ。情報が二重化すると、それらの間で不整合が生じバグの原因になる。また、二重化した情報は、修正の手間が二倍になる。
たとえば、ユーザーのプロフィールを管理するレコードやクラスに「生年月日」と「年齢」を同時に保持する必要はない。年齢は生年月日から計算できるからだ。
世の中には、「xxxFlag」みたいな不要な変数を作ったり、共通のロジックを抽出せずにコピペコードを濫造するダメプログラマーが多すぎる。
もちろん、合理的な理由があって、この原則が適用されない場合もある。
たとえば、多くの言語組み込みの配列や文字列は、その要素と長さを二重に管理している。配列の長さは要素を数え上げることで求まるが、それには要素数に比例した計算時間がかかるためだ。
ただし、こういう場合でも、公開されたメソッドによる操作では、必ず内部の変数は同期されるように作ることが可能である。それをしないのは、怠慢でしかない。
一文字変数とか連番とかは論外だが、「ary」とか「setData()」みたいな何の情報も伝えないような変数名・関数名を付けるやつ。
正直、コードの読みやすさなんて6〜7割くらいは変数名の付け方で決まると思っている。
名著「The Art of Readable Code」も、半分以上が変数名の付け方に関連する内容だ。
なぜ変数名が曖昧になるのかと言えば、怠慢を除けば理由は2つある。
1つは、コードを書いた奴自身が、そのコードの機能を明確に言語化できないということ。
もう1つは、1つの関数で多くのことをやりすぎたりしていて、その変数の役割が曖昧になっているということ。
たとえば、関数の内部で宣言した変数は、多くの言語では関数の外からは参照できない。
スコープは狭い方が良い。これはほとんど全ての状況に適用できるプログラミングの大原則だ。
スコープが広いということは、ソースコードの多くの場所からその情報を参照・変更できることを意味する。
たとえば、クラスのメンバ変数は各々のインスタンス内でしか参照できないが、静的な変数はすべてのインスタンスが共通に持つ。このため、静的な変数を変更すると、すべてのインスタンスに影響を及ぼし、影響範囲の把握やテストが困難になる。
スコープを広げるか狭めるか、2つの選択肢があったとして、広げる方に心が傾く奴は、プログラマをやめた方がいい。
結果的にメンテナンス困難なコードを生むというのも勿論だが、単に書くだけでも、スコープが広い方が書きづらいのだ。つまり、必要もないのにわざわざ変数のスコープを広げようとする奴は頭のおかしい奴しかいないということになる。
複雑なメトリクスなどを持ち出すまでもなく、たとえば1メソッドの行数が何百行もあるとか、1クラスのメンバ変数が何十個もあるとか言うの。
これは論外である。プログラマとしての能力云々以前に、明らかな怠慢であり、社会人としての常識が疑われる。
定期的にメンテナンスされ続けているOSSのソースコードなどを見ると、関数(メソッド)の行数は平均して5〜10行。20行を超えるものは稀である。
長いものであっても、外部で定義した関数を順番に呼び出しているだけであったり、リクエストをハンドリングして各々の処理に振り分けているだけのようなものがほとんどである。
それを超えているコードは、合理的な理由があってそうなっていることよりは、単に悪い設計であることの方が多い。
これらは実はプログラミング云々というより、内容の理解力や国語力の問題なのである。
ある情報を得るために必要十分な情報は何かが分かってないから、余計な変数を作ったり、無駄に変数のスコープを広げたりする。
そして、自分が作るものを正確に理解していないから、適切な名前がつけられないし、適切なモジュール分割ができない。
それがすべての原因。
こういう人がまず身につけるべきは、プログラミングのテクニックではなく、日本語を正しく読む力。
低学歴が「プログラミングなら自分でもできるかも」なんて思っちゃいけないってこと。もちろん、下請けのSIerとかで使い捨てのコード書きとして働くことはできるが、上に書いたような最低限の力がないなら、それ以上を望んではいけない。
ちなみに、上に書いていることと反対のことを思っている人も世の中にはいる。
特に、昔からプログラミングをしてきた自称ベテランに多い。その人は、能力があるというよりも、単に現代の開発に際して必要な知識がないだけなので、真に受けないように。
また、大学でコンピュータサイエンスの基礎を学びたての学生なども、知識をひけらかしたくて上と反対のことを言う傾向がある。その程度のことは、良識のあるプログラマはみんな分かっているのだが。
グラビアのスキャン画像を蒐集する趣味を楽しんでいた時期がある。
グラビアと言っても日本の週刊誌やアイドル雑誌のグラビアではなく、主に海外のソフトコア雑誌やセレブ誌のグラビアである。
飽きてやめてしまうまでの数年間、日本人の同好の士とは出会えなかったので、たぶん日本人でそれをしていた人はごく少数だったんじゃないかと思う。
自分はただのエンジョイ勢だったのでそれほど深い知識があるわけじゃないけど、日本語の文献も見つからないようだし、思い出としてちょっと書き留めておこうと思う。
だいたい20年くらい前の昔話。
よくわからないが、Online Scan Collection とか scanz(warezのノリ?)と呼ばれていたと思う。
スキャナーと呼ばれる職人が配布する画像ファイル(主にグラビア)をコレクターが集めたり、コレクター同士でトレードしたりする遊び。スキャナーはコレクターを兼ねていたりもするし、コレクターがスキャナーとなって配布を始めたりもする。
配布される画像はスキャンと呼ばれる。紙媒体で売られている雑誌のグラビアを高解像度のフラットベッドスキャナで読み取り、もとが印刷物であったことなどわからないくらい美麗にレタッチされたJPEG画像である。600dpiクラスのスキャナと高機能のレタッチソフト(ほぼPhotoShop一択)がたぶん必須。
題材は大半がセクシーな女性のグラビアで、ヌードでもPLAYBOYやPENTHOUSEに載る程度のおだやかなもの。水着、下着姿のものも多い。が、たまに美しい風景のシリーズがあったりもする。
画像の片隅にはそれを作ったスキャナーのシグネチャ(かっこいいアイコンなど)がウォーターマークとして付される。
あ、上で「日本人はごく少数」と書いたが、おそらく日本人だろうというスキャナーはいた。中でも印象に残っているのは Kuni Scan という2万枚ほどのシリーズで、題材が日本のグラビアだったし名前からして日本人だろう。Kuni Scan で画像検索すると今でも彼の作品の一部を見ることができる。
今でもそうだが印刷物をスキャンして配布するのは明白にコピーライト違反であるし、ことに題材が肖像権にがっつり抵触していることもあって、一次配布はきわめて目立たないかたちで行われていた。
スキャナーたちが「新しいのできたよー」と最初の配布を行うのはおそらくIRCチャンネルだったと思う。自分は外人たちと英語でリアルタイムのチャットをする自信がまったくなかったのでIRCにはほとんど近寄らなかった。なので一次配布の現場のことはよく知らない。
当時はimgurのような匿名画像アップロードサイトなどもなかったのでこのような個人間のやりとりで配布が行われていたのだろうと思う。
この時、スキャナーは画像とともにスキャンリストも一緒に配布するのであるが、それについては次で述べる。
スキャンは数十枚~100枚程度のテーマを持ったシリーズとしてリリースされる。テーマはモデルであったり、雑誌であったり様々。
最新リリースには必ずそのシリーズに含まれるファイルの一覧を記したCSVが添えられる。
リストに記されているのは [ ファイル名, ファイルサイズ, CRC32 ] の3項目(CRC32はファイルの指紋のようなもので、データの同一性を確認するのに用いられる通信技術)。
この3項目が一致していないとオリジナルデータと認められず、集めたことにならない。
たとえばWebで目当てのファイル名の画像を見つけたとしても、それが何者かの手によってリサイズされていたり再圧縮されていたりするとCSVと数値が一致せず、コレクションに加えることができない。
シリーズには継続中のシリーズとすでに完結したシリーズがあり、CSVファイルに[finished]といった名前がついているのが完結したシリーズである。これに載っているスキャンを全部集めたらコンプリート。
CSVはこんな感じで今でも配っているのを見つけた。
http://www.scancollections.com/CSV/list_csv.php
(私がかつてひとつだけスキャナーとして配布したシリーズも含まれていた。なんだかうれしい)
一次配布時にIRCを通じてスキャナーから直接手に入れることのできなかったスキャンは別の手段で探すことになる。
Webにアップされているものを探したり、同好の士とトレードしたり、alt.binaries(ニュースグループ)でも交換が行われていたように思う。
私は主にWebサイト経由で集めていたのだけれど、当時個人ホームページの割り当てボリュームは数MB程度がふつうだったので、スキャンをアップしてくれるサイトも古いものはどんどん消されてしまった。しかも1枚1枚がやたらでかい。今でこそ一辺が1000ピクセル以上あるような大きな画像でも表示は一瞬だけれど、DSLすらなかった時代の混み合うテレホーダイのISDN回線では300KB程度のJPEGでも上からじわじわ表示されてくるのを待つ感じだった。
海外の同好の士からトレードを持ちかけられることもあった。トレカの要領。ロシアや台湾のコレクターと、お互い非母国語の英語でたどたどしく「おまえこれ持ってるか」「おれのこれやる」とトレードのやり取りをするのである。基本は1:1で持ってないもの同士を交換というタテマエだけど、自分は持っているものは気前よく差し上げていた。ドイツのコレクターとはたまたま音楽の趣味が合ったのでしばらく文通してたな。
そうやって新しく手に入ったスキャンがあると、コレクションマネージャーみたいなソフトを使ってCSVと照合する。CSVと一致しないデータを取り除いてくれたり、リネームやフォルダ分けを自動でやってくれたりするスキャンコレクションに特化した管理ソフトがあったのである。
自宅のネット回線をFTTH常時接続に変えたとたんにコレクションがつまらなくなった。
どんなサイトも画像もピュンピュン一瞬で表示されるし、コレクションがウン千枚詰まったZIPファイルですらたちまちダウンロードされて、「苦労して一生懸命集める」という手応えがなくなって、「やりがい」がなくなってしまったのである。
DSL、常時接続の普及にともなってネット上には高解像度データがあふれるようになり、スキャンでしか見ることのできなかった美麗画像の希少性がどんどん下がっていったこともあると思う。
「それ俺もやってた!」って人いますか?
LiveDoor認証がでたらしいので、とりあえず寝際にちゃちゃっと書こうとしたのだけどなんかうまくいかない。
「ログインURLの有効期限が切れています」とかでちゃうんだ。
なにか間違ってるかな?
<?php // LiveDoor認証に必要なリンクの生成 // 定数がクラス内に切ってあるので環境にあわせ変更してください include_once('authlivedoor.class.php'); // Livedoor認証用クラス $obj_auth = new AuthLiveDoor(LIVEDOOR_APIKEY, LIVEDOOR_SECRET); $livedoorloginurl = $obj_auth->getLoginUrl(); ?> <div style="border:solid 1px #666666;"> <a href="<?= $livedoorloginurl ?>">ライブドア認証を利用してログインする<br /> <img src="http://auth.livedoor.com/img/cmn/head_livedoor.gif" border="0"> <img src="http://auth.livedoor.com/img/cmn/head_logo.gif" border="0"> </a><br />
<?php // this code is writen by utf-8 & lf //http://auth.livedoor.com/login/?app_key=<app_key>&perms=<perms>&t=<time>&v=1.0&userdata=<userdata>&sig=<sig> // LiveDoor外部認証APIを利用する // キーは各開発者ごとに取得が必要です。 http://auth.livedoor.com/ ここより取得できます。 // コールバックURLには authlivedoor.php を指定してください // --- 下記宣言を環境に合わせて変更してください。 --- define("LIVEDOOR_APIKEY" ,""); // アプリケーションキー define("LIVEDOOR_SECRET" ,""); // LiveDoor認証秘密キー // --- ここまで --- class AuthLiveDoor { const LIVEDOOR_AUTH_PORT = 80; // ポート const LIVEDOOR_AUTH_TIMEOUT = 10; // タイムアウト const LIVEDOOR_AUTH_VERSION = '1.0'; // 認証APIのプロトコルバージョン const LIVEDOOR_AUTH_PERMS = 'id'; // 認証APIのアクセス権 const LIVEDOOR_AUTH_FORMAT = 'xml'; // 認証APIの取得フォーマット const LIVEDOOR_AUTHURL = "auth.livedoor.com"; // LiveDoor認証URL private $login_state = false; private $login_id = ""; private $err_msg = ""; private $apikey = ""; private $secret = ""; public function __construct($apikey, $secret) { $this->apikey = $apikey; $this->secret = $secret; } // // $cert = $_GET['token']; public function getAuth($token) { if ($token == "" ) { return; } $api_time = date('U'); // エポック秒で $param_ary = array($this->apikey ,AuthLiveDoor::LIVEDOOR_AUTH_FORMAT ,$token ,api_time ,AuthLiveDoor::LIVEDOOR_AUTH_VERSION ); sort($param_ary); $api_sig = hash_hmac('sha1',implode('',$param_ary),$this->secret); $param = "app_key=".$this->apikey ."&format=".AuthLiveDoor::LIVEDOOR_AUTH_FORMAT ."&token=".$token ."&t=".$api_time ."&v=".AuthLiveDoor::LIVEDOOR_AUTH_VERSION ."&sig=".$api_sig; $fp = fsockopen(AuthLiveDoor::LIVEDOOR_AUTHURL , AuthLiveDoor::LIVEDOOR_AUTH_PORT , $errno , $errstr , AuthLiveDoor::LIVEDOOR_AUTH_TIMEOUT); if (!$fp) { $this->err_msg = "$errstr ($errno)<br />\n"; } else { $out = "POST /rpc/auth?$param HTTP/1.1\r\n"; $out .= "Host: auth.livedoor.com\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); $ret = ""; while (!feof($fp)) { $ret .= fgets($fp, 2048); } fclose($fp); } // LiveDoorの認証XMLのパターン $pattern = '/(\s*<livedoor_id>)(.*)(<\/livedoor_id>)/'; preg_match_all($pattern,$ret,$getAry); $livedooruserid = $getAry[2][0]; // ユーザーIDを取得できた場合 if ($livedooruserid != "") { // ログイン成功 $this->login_state = true; $this->login_id = $livedooruserid; return ture; } } public function getLoginState(){ return $this->login_state; } public function getLoginId(){ return $this->login_id; } public function getLoginUrl() { # http://auth.livedoor.com/guide/ # http://auth.livedoor.com/login/?app_key=<app_key>&perms=<perms>&t=<time>&v=1.0&userdata=<userdata>&sig=<sig> # app_key 必須 登録時に発行されたアプリケーションキー # perms 必須 要求するアクセス権、現状userhashとidの2種類がある # t 必須 URLが生成された時間をエポック秒で表したもの # v 必須 プロトコルバージョン、現在は1.0で固定 # userdata 任意 コールバックURLに引き継ぎたい値を255バイトまで自由に設定できる # sig 必須 このURLの正当性を確認するためのシグネチャ // ログインURLの有効期限が切れています // ヾ(。o、゜)ノ ここらへんがわからん!! // $api_time = time()+32400; // エポック秒で $api_time = date('U')+32400; // エポック秒で // $api_time = date('U'); // エポック秒??もしかして、それはポエティック病ではありませんか? $param_ary = array($this->apikey ,AuthLiveDoor::LIVEDOOR_AUTH_PERMS ,api_time ,AuthLiveDoor::LIVEDOOR_AUTH_VERSION // ,data ); sort($param_ary); $api_sig = hash_hmac('sha1',implode('',$param_ary),$this->secret); $loginurl = "http://auth.livedoor.com/login/" ."?app_key=".$this->apikey ."&perms=".AuthLiveDoor::LIVEDOOR_AUTH_PERMS ."&t=".$api_time ."&v=".AuthLiveDoor::LIVEDOOR_AUTH_VERSION // ."&userdata=" ."&sig=".$api_sig; return $loginurl; } }
もう疲れたので寝る。ライブドアなんてーーーー!!!
訂正。
秘密キーとか、そのままのっけちゃった (ーωー|||)
そしてなかなか訂正できなくてあせった。。