2017年8月21日月曜日

今こそ、プログラマの時代


・ブログ( ドッと混む・Knuhsの書斎 )から転載

── プログラミングの勧め

▼小学生へのプログラミング教育
 小学生への「プログラミング教育」必修化が検討されているという。
 私が育ったアナログ世代とは異なり、デジタルネイティブ世代を相手にする教育だから、教え方にもそれなりの創意・工夫が必要になるのではないかと思う。どのような教え方をするのか興味のあるところだが、そう簡単にベストの方法が確立されるとは思えない。失敗を繰り返しながら少しずつ良い教育方法が築かれていくことになるのだろう。

 どの世代が相手であろうと「プログラム作りに必須の技能」としてプログラマなら身に付けなければならないものがある。そういうものは適当な時期を選んでしっかりと教え込んで欲しいものだ。

▼分かりやすい文章
 たとえば「分かりやすい文章」を書く能力が求められる。プログラム作りに限らず最も基本的で必須の能力であるが、小学生が直ぐ身に付けられる類いのものとは思えない。

 どんな言語でも構わないが、日本語、英語、あるいはコンピュータ言語、何でも良いから「自分の考えを抜かりなく、誤解の余地なくしっかりと相手に伝える」ことができるようになってほしい。それができなければ、相手がであろうとコンピュータであろうと思い通りに動かすことなどできる筈がない。

▼誤解を与える
 政治家はよく「誤解を与えた」という表現を使って弁解しようとするが、これは「相手が間違って解釈したのだ」と主張し責任の大半を相手側に押し付けようとするものである。

 しかしそんな身勝手な言い分けはプログラミングの世界では通用しない。プログラムの記述で「誤解を与えた」としたら、それは自分の表現方法が間違っていた、あるいは自分の説明が足りなかったということを意味している。全責任は自分の側にあると知るべきであろう。

▼定年という壁
 ところで、私が定年を迎えて技術者としての職を辞さねばならなくなったとき、自分ではまだまだ技術者として生きていけるのに、と悔しい思いをしたことを覚えている。しかし今の社会はそういう制度になっているのだから仕方がない。更に続けたければ自分で会社を興すしかないのだろう。そういう才覚のない私めは、定年がなく長く続けられる仕事として芸術家の道を選べばよかったと思ったものだ。あるいは小説家になるという手もあった。たとえ売れない作家であっても、定年がなければ自分の気の済むまで仕事を続けられる。

 私はこれまでの経験から「プログラミングというのは文章を書くのと同じことだ」と思うようになっていた。「自分の考えを抜かりなく、誤解の余地なくしっかりと相手に伝える」ことができればよいのだと。それなら私にも続けられる。小説家になろう。いや、小説家にならなくても、プログラミングの道があるじゃないか。

▼昔プログラマ
 これ以後、私は大学教師としての職についたのだが、同時に「昔プログラマ」を自称するようになった。昔はプログラマだったが、今はもうプログラマではありませんよ、という意を込めた積りだった。しかし本当のところは「プログラマ」という肩書に執着していたのかもしれない。

(図:名刺)

 大学教師というのは実は世を忍ぶ仮りの姿であって、本当のところはこっそりとプログラマの積りになって、プログラム作りを続けてきたのである。教師としての自分の身辺で発生するいろいろな問題の解決にコンピュータを利用してきた。しかし誤解の無いように記しておくが、自分の身辺に係わる問題だけが対象であって、他人のための仕事をしてきた訳ではない。

 教材として使うテキストの作成、課題提出システムの構築、その他自分の趣味に関係するゲームプログラム(!)の作成も含まれている。金儲けが目的ではないから、自分に関心のあることだけを、誰の許可を得るまでもなく自分だけの判断でできるのだ。これほど自由な仕事はない!
 その間、いろいろなプログラム言語を勉強し活用してきた。C/C++, Perl, Javascript, VBA, ...

▼ソフトウェア危機
 昔「ソフトウェア危機」という言葉が叫ばれるようになった時代があった。コンピュータが強力になり、大きなソフトウェアの開発が必要になってきたのである。この調子で進むと沢山のプログラマを養成しなければならない。いや、日本の全国民をプログラマにしてもまだ人数が足りなくなると予想される事態になったのである。全国民であるから当然、赤ん坊も人数に含まれていた。

 赤ん坊プログラマをどうやって教育しようと考えていたのか、そこのところは明らかでないが、この問題提起のお蔭で「ソフトウェア工学」という分野が切り開かれ、当面の危機を免れることができたのである。

 このときは赤ん坊プログラマが話題になったが、流石に高齢者をプログラマにするという発想は出てこなかったと記憶している。何となれば、当時コンピュータの世界では「38歳定年説」というのがあって、ソフトウェア技術者が40歳以上でも務まると思っている人はいなかったからであろう。

▼高齢者プログラマ
 しかし今や、高齢者の雇用促進が求められている時代である。定年後も年金受給が可能になるまでの期間、どのように生活していったらよいかも問われている。たとえ雇用されなくても、有意義に過ごすテーマが必要ではないかと思う。

 私は、高齢者もプログラマを目指したらよいのではないかと提案したい
 定年後もプログラミングをしたいというような酔狂な人は少ないかもしれないがゼロではなかろう。昔、ソフトウェア技術者だった高齢者にもプログラマとして復活する道があっていいのではないか。

 高齢になっても小説を書き続けている作家は沢山いる。評判になるのはほんの一部の作家だけで、その陰には売れない作家も沢山いるに違いない。
 昔のプログラマにもプログラミングの道があるじゃないか。小説家に劣らず、プログラマになれる人材は沢山いるに違いない。売れない小説家がいるのなら、売れないプログラマがいてもいいじゃないか!
 しかも、プログラミングはボケ防止に最適なんですよ。

▼高齢者プログラマの心構え
 高齢者プログラマを目指すなら、次のような注意が必要である。

(1)金儲けは考えない
 高齢者は電話詐欺の餌食になりやすい。自分が作ったプログラムが他人に評価されるのはうれしいことではあるが、他人からの「いいプログラムですね。売れますよ!」とか「買ってくれる人を紹介しますよ」などという甘言に乗ってはならない。したがって金儲けをしたいという考えがあったら止めておくことです。

【注】私は公開するプログラムはすべて無料で使ってもらうことを前提としています。すべてのプログラムには「Copyleft」のマークを付けることにしています。

(2)短編小説をねらう
 企業でソフトウェア開発の経験があったからと言って同じような大型物件の開発に挑戦したりはしない方がよい。あれは大河ドラマのような大長編小説であって、一人で作るのなら短編小説、あるいはショートショート程度にしておくことである。

(3)手頃なプログラム言語を用いる
 使用するプログラム言語は、若い時代に使用した言語が馴染み易くていいかもしれない。しかしできるだけ無料で手に入るものに限定すべきである。

【注】私は60歳代になってからPerlを勉強しました。文法規則を守り厳密に記述しないと受け付けないモードと、いい加減に書いて「良きに計らへ」とシステムに任せられる怠け者向きのモードがあって、私のような怠惰な男には最高の言語なんです。お奨めしますよ。

▼作品の公開
 私の作品は、以下の場所に公開されています。参考にしてください。

 「Perl Program集

「昔プログラマ」改め「昔も今もプログラマ


2017年8月16日水曜日

(昔プログラマの) プログラミング奮戦記(その2)

・ブログ( ドッと混む・Knuhsの書斎 )から転載

── JPEGファイルの解剖と解析

▼JPGファイルの解読
 先の「JPEG画像から縦横のサイズを取り出す(昔プログラマのプログラミング奮戦記)」で紹介したようにデジタルカメラに記録された画像データから、付随する情報を読み取るプログラムをPerl言語で記述しようと試みてきた。この種のファイルはJPEGファイルと呼ばれているが、いろいろな形式がある。ここでは、Exifファイルフォーマットと呼ばれ規格化されているものを対象としている。

▼Perlプログラムでの処理
 先に紹介したプログラム(*1)の中で使われている GetJPGsize という関数を使うことにより、画像の横の長さ縦の長さを求めることができるようになった。

 これが使えると、手作業によらないで沢山の画像ファイルに対し一括して適用できるようになり大変な省力化になる。しかし残念ながらこの関数の記述では、複数のJPGファイルに対し繰り返し適用しようとすると2度目以降はうまく動作しないという不都合が発生してしまう。つまりこの関数では、繰り返し同じ機能を発揮してくれないのである。
 プログラミングの世界では、こういう状況を「reusableでない」と言う。reusableでない関数は、全くとは言わないまでもほとんど利用価値がない。
【注】(*1)これまで、GetJPGsize.pl というファイル名にしてきたが、関数名とファイル名を区別するため、以後ファイル名は AnalizeJPG.pl とする。
 不都合が発生する原因をいろいろと追究してきたが、原因は未だに解明されていない。文字コードを扱うのが専門のPerlという言語で、無理やり処理しているのが原因なのかもしれない。Perlでこの種のデータをただやみくもに読み込んだりすると、データの一部が壊される可能性があるからである。たとえばデータの中に改行コードがあると、Perl処理系は実行環境に合わせて変換するのが普通である。

 Perl では改行は '\n' と表現されるので,一文字から成るように見えるが、実行環境によっては1文字(CR)の場合、あるいは2文字(CR+LF)の場合と違いがある。それぞれに実行環境に合うよう自動的に置き換えられる。したがってただ無暗に読み込んだりすると、たまたま制御コードと同じパターンのデータがあれば、誤って変換され結果としてデータが壊されてしまうことになる。そういうことにならない様、ここではライブラリ関数の read ではなく sysread の方を用いることにした。更に、データ構造をしっかりと確認し、画像を構成する本来のデータ部分はできるだけ触れない(読まない)ようにすることにした。

▼JPGファイルの構造を学び直す
 ここで、JPGファイルの構造をしっかりと学び直すことにした。
 インターネット上で「JPGファイルの構造」とか「Exifファイルフォーマット」を指定して検索すれば有益な情報が得られる。

 現時点で公表されている資料では、Exifファイルフォーマットのバージョンは v2.1 と記されているものが最新のようである。残念ながら私の使っているカメラでは、Exifファイルフォーマットはv1.1であるから古い仕様であることが分かった。

 素人カメラマンの私にとって、ファイルフォーマットが古いからと言ってそう簡単にカメラを買い替える訳にはいかない。したがってここでの説明は最新の仕様に沿うものではないので、もしかすると互換性がない部分があるかもしれない。以下は考え方だけを理解してもらえばよいので簡単な説明で済ますことにしよう。

▼解剖と解析
 方針として、先ず全体の「解剖」(JPGvivisect.pm で処理)を行って、その後で個々に「解析」(AnatomyJPG.pl で処理)するという手順を取ることにした。ただし、呼び出しの手順は AnatomyJPG.pl から JPGvivisect.pm を呼び出すようになっている。
(図1:処理の手順)

 JPGファイルでは、本来の画像データの前に情報セグメントが複数個置かれている。
(図2:JPGファイルの構造)

 この「情報セグメント部」に属する「各情報セグメント」の「種類」と「位置関係」を明確にする必要がある。つまり解剖して各セグメント(内臓)の種類と位置と寸法が分かるようにする。そして全体の骨格が明確になった後で、初めて個々のセグメントの中を解析することにする。

▼解剖プログラム(JPGvivisect.pm)
 解剖プログラムは最も基本的なプログラムなのでパッケージ化し、ライブラリとして使えるようにしてある。

 この「解剖結果」を記憶する場所として %HashTBL という名のグローバルなハッシュ変数を用意する。グローバル変数なので他のモジュールからもアクセスできるようになっている。

 各セグメントは先頭にはマーカー(2バイト)があり、次に長さ情報(2バイト)が置かれている。この値がマーカーに続く情報部分(セグメントパラメータ部)の長さである。つまりこの2バイトの長さを置く場所も情報部分に含まれる。
(図3:セグメントの構造)

 %HashTBLというハッシュ変数をどのように使うかを説明しよう。
 ハッシュ変数というのは、<キー><値>を対にして記憶するものであるが、%HashTBLでは<キー>として JPGファイルのセグメント情報を示す「マーカー」を利用する。<値>としては、そのマーカーの<位置情報>を記憶する。

(表:代表的なマーカーの一覧)
Merker
Code
SOI(Start of Image) FFD8
APP0(JFIF) FFE0
APP1(Exif) FFE1
APP1(Exif) FFE1
DQT(Define Quantization Table)FFDB
DQT(Define Quantization Table)FFDB
SOF0(Start Of Frame 0) FFC0
DHT(Define Huffman Table) FFC4
DHT(Define Huffman Table) FFC4
DHT(Define Huffman Table) FFC4
DHT(Define Huffman Table) FFC4
SOS(Start Of Scan) FFDA
EOI(End Of Image) FFD9

 ただし、同じマーカーが繰り返し登録される可能性もあるので、<位置情報>には登録個数とそれぞれの位置情報を保存できるようにする。そのため、値はリスト形式にしてある。
  ( [0], [1], [2], [3], .... )
[0]に登録個数、[1]以降に位置情報が置かれる。  最初に

  $HashTBL{ <キー> }[0];

とするとマーカーが%HashTBLに登録され、値を置く位置の[0]はまだ空であるがPerlでは空はゼロと解釈されるので、

  $i = ++$HashTBL{ <キー> }[0];

と書いておけば [0]の値が 1 に、$i にも 1 が代入される。

次の行の

  $HashTBL{ <キー> }[$i] = <位置情報>;

<キー>に対応する<位置情報>[$i]つまり[1]の位置に保存される。
以下同様にして、登録のたびに[0]に個数が
それぞれの位置情報が[1],[2],[3],[4],...
に保存されていく。

▼解析プログラム(AnatomyJPG.pl)
 解析段階では、この解剖段階で得られた情報を使って一般の利用者(カメラ愛好家)が必要とするであろう各種情報を得られるようにする。得られた「解析結果」は %DataTBL という名の、これもグローバルなハッシュ変数上に保存し共用されるようにする。
 解析結果を記憶したければ、適当に識別名を付けて値を代入すればよい。

 $DataTBL{'File Name'} = "$fileString";

 例えば、SOF0('FFC0')マーカーに属するデータを得たければ

 $pos =$HashTBL{'FFC0'}[1];
 
として'FFC0'マーカーの位置情報を取り出し getByte関数を使ってセグメントパラメータ部から値を取り出す。

 $H = getByte($pos+5,2);
 $W = getByte($pos+7,2);


 これらを $DataTBLに保存するときは、数値にコンマを挿入(insCom関数)したり、数値の単位も合わせて記録しておくと利用するときに便利である。

 $DataTBL{'横幅'}=insCom($W)." Pixel\n";
 $DataTBL{'高さ'}=insCom($H)." Pixel\n";

 詳しい技法については、

  解析プログラム(AnatomyJPG.pl)

  解剖プログラム(JPGvivisect.pm)

を参照してください。