プログラミング入門

プログラミングの基本

SEの仕事は問題を解決すること

システムエンジニアの仕事は、「問題を解決すること」です。
まず、要求されている問題を明確に定義します。顧客の要求を考えたり、実際の現場から何が問題として求められているのかを考えます。
そして、どのようなシステムを構築すれば問題を適切に解決できるかを明確にします。
次に、そのようなシステムをどのようにすれば構築できるかを考えます。
その後に、システムの設計を行い、設計からプログラムを実装し、コードを書きます。
そして、テストし、納品し、システムの保守を行います。
実際のところ「コードを書いている時間よりも、考えている時間の方が多い」とよく言われます。
また、プログラミングとは、「問題を解決する」ことそのものです。どのように計算し、操作し、処理し、実行すれば問題の「ソリューション」(解決方法、答え)を与えられるかを考えるのです。

数値の変換

プログラミングにおいては、「数値の変換」という発想がよく起きる。
たとえば、「入力された文字を人数分表示する」というプログラムがあったとして、ここでは、人数が表示回数に変換されている。
人数が3人居たとして、その3人がそのまま3回になる。このように、「ある数字が別の数字の元になる」。10人居れば10回になる。3×10という単純な計算を、プログラミングではそのように行う。それぞれの人数だけ行うように、それぞれの数を別の数にする。あるいは、条件式や分岐にすることもある。

入念に作っておいて、あとは何度でも再利用できる

プログラミングを行うよりも、手動で操作した方が簡単にできることは確かにあります。
たとえば、テキストエディタで検索・置換を行ったり、行ごとにカウントして処理したりすることは、確かに手動でも行えます。
しかしながら、プログラムの真価は再利用できることにあります。一度自動化してしまえば、あとは何度でも再利用できるのです。
そのため、テキストエディタを使うところをRubyを使うようにするだけで、作業ははるかに楽になります。たとえば、ファイル一覧を得るPHP/Rubyなどの関数であるglob()などを使うことで、ひとつのファイルだけではなく、多くのファイルを簡単に操作することができます。

構成や設計を作る能力をつける

プログラミングを行う上で必要なのは、構成や設計を行う能力です。
たとえば、オンラインショッピングサイトを作るような「やり方」を学ぶことで、学ぶだけではなく実務的なプログラミングができるようになります。
これについては、Railsのようなフレームワークで実際のやり方を学んだり、本を読んでやり方を学ぶこともできますが、以下に挙げるプログラミングスクールに通うのもおすすめです。

プログラミングスクール

方法として言えるのは、リナックスアカデミーや侍エンジニア塾やGEEKJOBやプログラマカレッジなどのプログラミングスクールに通うことです。
授業料は高いですがリナックスアカデミーの評価はおおむね良しです。お金があるならおすすめします。

アーキテクチャ概念の構築

また、プログラミングについて言えるのは、「アーキテクチャ概念の構築」です。
たとえば、MozillaXULや、RailsMVCフレームワークなどがこれに当たります。
プログラミングは、単に作るものの枠組みを考えてコードを書くだけの作業ではありません。自分の考えたアーキテクチャ概念を「発明」するという仕事なのです。
ですので、ただのコードを書くだけの「コーダー」と呼ばれるエンジニアではなく、アーキテクチャを創造する「アーキテクト」になってください。アーキテクチャを創造するためには、プログラムの全体像の設計や構成ができることに加えて、必要となる技術やプラットフォームやシステムデザインに精通し、プログラミング以外の能力も必要になるでしょう。

ハードウェアではなくプログラミングで実現する

日本人の科学者である嶋正利Intelが一緒になって作ったIntel 4004以降の「マイクロプロセッサ」では、CPUは基本的な演算機能だけを提供し、あとの多くの機能を「プログラミング」によって成り立たせる、という新しい考え方を作りました。
これは、今のプログラム開発についても当てはまります。基本のCPUの機能は少なく、「原則プログラミングで機能を増やしていく」という発想です。
WebブラウザSleipnirのように、WindowsGUIアプリケーションには、こうした考え方が色濃くあります。原則、プログラミングとは、「プログラミングによって付け足せる機能をどんどん付け足すこと」に他なりません。CPUのレベルで、プログラミングは機能をいくらでもソフトウェアで付け足していく、ということなのです。

Udemy

先に「プログラミングスクール」について書きましたが、Udemyという有料ながら良質なプログラミング入門コンテンツ(動画講座)を配信しているサイトがあります。

実際、プログラミングスクールに通うには高額な授業料が必要で、コスパが悪いです。Udemyの動画は内容が詳しく、内容に比べて安いのだと思います。

プログラミングについて

そもそもコンピュータはプログラミングをする機械

Windowsなどの影響で、アプリケーションを使ったり、ファイルシステムやネットワークを使ったりする、「OSを使うことがパソコンだ」と思っている人が、最近は多いと思います。
ですが、パソコンは使うだけではありません。パソコンとは、「プログラミングをする機械」なのです。
プログラミングは、文字列ばかり記述して、動いても面白くないし、きちんと書いたつもりでも最初から動くものは作れないため、「プログラミングはつまらない」と思う人が多いでしょう。
ですが、言ってしまえば、「プログラミングをしなければ、パソコンを使っているとは言えない」のです。
たとえば、科学技術計算をしたり、ゲームを作ったり、Webサービスを構築したり、フリーソフトを作ったり、といった全てのパソコンの関連分野は、プログラミングによって成り立っています。
決して、プログラミングは楽しいだけの作業ではありませんが、プログラミングをやりたいのであれば、「実際のプログラミング言語で書いてみる」ことです。それは、「OSを使うということとは全く違う」ということを知っておきましょう。OSのような優雅でかっこいいソフトウェアは最初から作れません。最初はPythonでHello, Worldが表示されるだけであり、「なんでこんなものが楽しいのだろう」と今のパソコン世代は思うと思います。ですが、テキスト処理やファイル処理、ネットワーク処理や人工知能などを通して、「なるほど、こんな感じにすれば動くのだな」と思うことで、「自分でコードを発明できる楽しさ」が見えてきます。パソコンは、簡単な計算でもプログラミングすることで実現します。「フロントエンドからコアのバックエンドまで全てを作って、優雅に動く喜び」が分かったら、あなたはプログラマとして、そしてハッカーとして初めの扉を開けたことになるでしょう。

焦らないこと、良く考えること、ゆっくり作り続けること

プログラミングをやる上で重要なのは、「焦らないこと」と「良く考えること」です。
たとえば、毎日継続してプログラミングを行う必要はありません。いったん動くコードを書いたら、そこで終わりにして、ひとまず休憩を入れて思索し、何か新しい発想をしたらその時に追記すれば良いのです。
継続して取り組むことより、ゆっくりと思いつきながら、深く考え広く調べながらやることです。
最初のプログラムを作って、次のプログラムを作るまでに、1か月かかっても良いのです。その間の期間は適当に過ごしましょう。考えていれば、何か新しいアイディアが思いつくでしょう。毎日思いつく必要はありません。自分のやりたいことだけを自分のペースでやっていけば良いのです。

Windowsもコードで動いている

Windowsプログラミングのつまらない点は、いつまで経っても文字列ばかりで、グラフィックスのかっこいいウィンドウシステムは作れそうにないことです。ですが、そうでもありません。Windowsと言っても、パソコンのプログラムにすぎず、つまり、「何万行の文字列」が動いているだけにすぎないからです。Windowsは、ファイル処理やウィンドウシステム、ツールキットのような部品が組み合わさって動いているように見えますが、実際に動いているのはプログラムにすぎません。Windowsも、ソースコードのレベルでは、ただの文字列にすぎないのです。これを「コード」と呼びます。
そう、全てのソフトウェアの裏側にはコードがあります。OSだけではなく、ファイルマネージャやウィンドウシステム、ウィンドウマネージャ、テキストエディタ、ツールキット、ブラウザ、サーバー側のWebサイトやHTTPサーバーまで、全ては裏側にコードがあり、それが実行されていることで、コンピュータ環境の全ては実現されています。「全てコードである」と思えば、理解できると思います。

オープンソース開発

ある意味、会社で何時間もプログラムを書き続けるのは、とてもハードで体力の居る作業ですが、オープンソースは片手間で、好きな時に作れば良く、またたくさんの人々が貢献しているため、みんなと協力すれば楽にプログラムが作れてしまいます。そのことが、Linuxのようなオープンソースの開発ソフトウェアを品質の高いものにしているのではないでしょうか。会社でデスマーチをするのは苦労が伴います。馬鹿なエンジニアの書いたコードを延々と直さなければいけません。オープンソースならば、自分だけで自由にでき、コミュニティでたくさんの人々の成果を自由に得られます。
オープンソースでコードを公開することで、全世界のインターネットユーザー全員にコードを公開することになりますが、この簡単な方法で、ソフトウェアの品質を高めることができます。ただコードを公開するだけで、人々はコードを読むことができます。それだけで爆発的な発展が起きる、それがオープンソース革命だと良く言われましたが、実際のところ、オープンソースはきちんと動くインフラ製品を提供するようになりました。ですが、オープンソースであることはとても良いことです。先に書いたように、プログラムの実行の裏側にはコードがあります。そのコードにアクセスできることが保証されることは、学習や教育のために良いことではないかと思います。
会社の社員だけがコードを見るのと、全世界の全員がコードを見るのとでは、雲泥の差があります。決してオープンソースが正しいわけではありませんが、できるだけ多くの人にコードを公開することで、品質が高くなる、ということはあると思います。
後日注記:僕はある意味、オープンソースやインターネットには、自然淘汰の原則が発生していると思う。馬鹿なサイトや馬鹿なソフトウェアは、誰にも使われず自然に消えていく。本当に正しい情報とソフトウェアだけが普及する。会社の書いたコードでは、馬鹿なコードでもそのソフトウェアに含まれていれば、使わざるを得ない。結果、代わりのものが開発されず、不安定でバグがいっぱいになる。ただし、最近のインターネットはおかしい。悪い噂やフェイクニュースなどが簡単に拡散してしまう。そうした「確からしさが失われた世界」では、きっとオープンソースなソフトウェアも全て、間違ったものになるのではないかと僕は思う。

低レベルと高レベル

本当のことを言えば、Windowsはとてもつまらないシステムです。それは、多くが「Windowsというコアシステムに命令しているだけ」だからです。
Windowsには多くのコンポーネントがありますが、そのコンポーネントに対して命令しているだけで、多くの場合プログラミングができてしまいます。
これは単純かつ便利なシステムで、Adobe製品などを作る上では楽でしょうが、プログラマからしてみれば、「結局Windowsを使っているだけに過ぎない」ということになります。
これに対して、Linuxカーネルが面白いかというと、そうでもありません。
Linuxカーネルは、基本的にハードウェアの操作しかしません。Windowsと同様、Linuxカーネルに命令することでプログラミングを行います。
違うのは、Windowsと比べて、「記述が美しい」とか、「コンポーネントが分離・整理されている」ということであり、あまり変わりません。
では、面白いプログラミングとはどこにあるのか。それは、「低レベルと高レベル」という話になるでしょう。
ハードウェアに近くなりすぎても、ハードウェアの仕様を実装するばかりで意味はなく、ユーザーや数学的な記述に近くなりすぎても、機能を使うだけで意味はありません。
ビル・ゲイツリーナス・トーバルズなら、「バックエンドもフロントエンドも全て設計・実装して分かる」ということができますが、それはとても根気の要る作業です。
結局のところ、どこかで折り合いをつけてバランスを保つしかありません。低レベルのハードウェアも高レベルのシステム操作もできるようになれば、それがプログラマという職業であると言えるでしょう。

パソコン操作、プログラミング、OS内部、ハードウェア、数学

そう、結局のところ、パソコンとは「機械を使うこと」にすぎません。ですから、OSをただマウスやキーボードで操作していても、それをコードの中でOSや言語やライブラリを用いた記述をしていても、OSの内部でハードウェアをマシン語で操作していても、それら全ては機械を使うことに過ぎない、そしてその機械は最終的にはハードウェアの中の電気信号と論理回路であり、半導体であると、そうなります。それが、パソコンの正しい「使い方」でしょう。本当のことは、物理学や数学のレベルにならなければ、見えてきません。だから、数学は高水準であっても低水準であっても、プログラマにとっては必要であると言えるでしょう。

プログラミングはバグとエラーとの永遠の戦い

プログラミングとは、特に経験や知識の乏しい初心者にとっては、「バグとエラーとの永遠の戦い」です。
そもそも、Windowsなどでもバグがいくらでもあるように、プログラミングにおいて、「動くわけの無いコードを何とか動くものにする」ということが、プログラミングの、特に初心者にとっての大きな時間を占めます。
バグやエラーが起きても諦めず、根気強く間違いさがしを行うこと、それが初学者がプログラミングを挫折しない唯一の心構えです。
オープンソースは、無保証かつオープンに無償でソフトウェアを多くの人に使ってもらいながら、みんなでバグを直して貢献する、という、一種の「バグ直しの開発共同体」であると言えるでしょう。

アルゴリズムの研究

変数・演算・条件分岐・繰り返しのフローチャートを描く

もし、あなたがアルゴリズムを研究したいのであれば、フローチャートを描くことが効果的だと思います。
フローチャートとは、処理の流れを分岐構造や反復構造などの制御フローによって表現した図で、条件と変数の演算の流れを大まかに捉えられます。
アルゴリズムを描く場合は、コードを書く前に、フローチャートにすることも、プログラムの設計の上で効果的だと思います。

プログラムとは、ルーチンを用意し、そこにデータを渡すこと

また、プログラムとは何であるかを一言で言ってしまうと、「ルーチンを用意し、そこにデータを渡すこと」ではないかと思います。
たとえばウィンドウシステムであれば、ウィンドウの中にフォームやダイアログを表示する機能が必要ですが、これを作るためには、「どんなフォームの画面データが来ても、適切な大きさでそれを表示する」ことです。
この時、具体的にどんなフォームであるかなどは考えません。することは、どんなフォームであっても対応できるように、あらゆるフォームを表示することのできるルーチンを書くことです。
サイズやタイトルなどのフォームに属するデータも同様です。どんなサイズであっても、あらゆるサイズでウィンドウを表示できるようにルーチンを用意し、そのルーチンに対してサイズの情報を与えれば、どんな場合でも動くようにするのです。
メッセージなども同様で、どんなメッセージでもフォームとやりとりができるようなイベント通信機能を作ります。具体的なメッセージについては、このメッセージ通達ルーチンを「作る時」ではなく「呼び出す時」に、さまざまなメッセージを「具体的に送る」ことができるようにします。そして、今度はこのルーチンを使って、さまざまなメッセージを具体的にイベントの通達やフォームの返答に対して対応付けし、最終的にサイズを変えられるようにしたり、フォームを再描画したり、クリックやキーボード入力などのイベント機構を作ります。
要するに、「どんなフォームの画面でも、どんなサイズやタイトルでも、どんなイベントメッセージでも対応できるような、正しいルーチンを書く」ことができれば、それだけでプログラミングはできるのです。
プログラムの設計とは、このように、「どんな場合でも対応できるようなルーチンを書く」ことです。実際に具体的なデータを操作することはなく、ただ単にあらゆるデータを操作できるようなルーチンを書けば、それでプログラムは完成です。
後日注記:このように「汎用的などんな場合にも対応するルーチンを作る」のは、ウィンドウシステムに限ったことではありません。たとえば、GTKやQtのツールキットならば、イベントを回収する「イベントを回収するコアルーチン」や、ツールキット全てに適用する「グラフィックスの適切な配置と表示のコアルーチン」などは、特にオブジェクト指向であればクラスの継承階層を用いて、「ひとつの汎用ルーチン」を書くことで実装できます。ボタンであれ、ラベルであれ、配置に必要なルーチンやマウスクリックなどのイベントに対応するためのルーチンは同じ「コアルーチン」を作れば作れます。よって、フォームへの配置は「どんなウィジェットでも配置して表示できるルーチン」を作り、マウスなどのイベントは「フォーム上のマウスクリックやキーボード入力をそれぞれのウィジェットに適切に配送するルーチン」などを作れば作ることができます。その上で、これらのルーチンをオブジェクト指向APIで、「ウィジェットの具体的な作成とイベントに対するコールバック関数の登録をプログラマが行うことのできるフレームワーク」を作る必要があります。
後日注記:また、印刷のためのルーチンでも、どんなページでも印刷できるようなプリンターへグラフィックスを送るルーチンを作れば作れますし、インタープリタコンパイラなら、一行の命令をどのように解釈するかを適切に判断する「文を解読するルーチン」を作れば作れるでしょう。実際には、ウィンドウシステムやツールキット、また印刷やインタープリタコンパイラには適切な「開発セオリー」があるため、「このように作ることが絶対に正しい」というものではありません。

プログラムとは

数式とプログラムの違い

数式とプログラムの違いとは、数式は「正しさや論理を表現する」記法であり、プログラムは「計算し関数を実行する手順」の記法である、ということです。
数式では、x=4+3ならばx-3=4であるといったように、その数と記号の書かれた意味から成り立つ論理の正しさを「表現」していきます。定理の証明を行う時でも、「表現」を中心に論理的に考えます。
ですが、プログラムは表現ではなく、計算の手順です。ですので、たとえば、

int x;
int y;
int z;
x = 3;
y = 4;
z = x + y;
z = z + 1;
printf("%d", z);

のように、まず使う変数を宣言して、それ以降は「どのように代入し、その代入をどのように変更し、いつどのように処理するかを逐次記述していく」という作業になります。
ですので、

x = x + 1;

のような、数式ではありえないような式もプログラムでは記述できます。逆に、4=1+3のような数式は、プログラミングでは書く意味がありません。
OSのやっていることは、このようなプログラムを管理し、実行するための機能を提供することと、プログラムに対してどのような機能を提供するか、たとえば入出力やメモリ管理、ネットワークやファイルシステムのような機能をプログラム側にどう提供するか、ということになります。これらはシステムコールとしてカーネルが提供しますが、一部の機能はカーネルではなく、ライブラリ関数やXサーバーとの通信プロトコル・ライブラリなどの、カーネルよりも上にあるプログラムが提供します。また、多くの場合プログラミング言語で書かれたプログラムの実行には、プログラムを機械語に変換するコンパイラや、逐次的に読みながらプログラムを実行するインタプリタを使います。

細かくなりすぎるぐらい、細かく書こう

プログラムの開発は、創造的な仕事に見えて、本当はとても細かい仕事です。
コンピュータは、指示・命令されたことを忠実に、少ない「命令されて出来ること」だけをやることしかできません。
プログラマは、コンピュータにも理解出来るぐらい、細かく、詳しく、正しく、全部をきちんと書くことしかできないのです。

制御が基本

プログラムの基本は制御です。変数と制御で、いつどこに流れが行くかを考えることで、プログラムは作られます。
知識を誇ることも大事ですが、制御とアルゴリズムもきちんと考えましょう。
おそらく、シングルタスクでは、制御がパソコンの基本ですが、Golangのような並列処理言語では、go構文を行うことで簡単にマルチタスクができます。先進的な非同期のシステムはそのようになるでしょう。

ノイマン型コンピュータと設計

現在のノイマン型コンピュータでは、「命令を逐次的に実行していく」ことしか出来ません。Lispのような関数型プログラミングや、Javaのようなオブジェクト指向プログラミングが出来ないわけではありませんが、現状のノイマン型コンピュータでは、全てのことを「命令の羅列」として実行・計算します。
そのため、C++であろうと、PHPであろうと、やることは同じです。プログラムから見れば、さまざまな記法を使いながら、計算の手順を具体的に書いていき、OSや言語・ライブラリの用意する関数を使いながら、「自分で設計するセンス」を持った上でプログラミングを行います。機械工学技術者とデザイナーの中間のような仕事がプログラマです。
ノイマン型コンピュータでは、どこまで言っても、プログラミングは「命令と記憶のやり取り」にすぎません。さまざまな計算をさせた内容を、記憶として保持し、関数に渡したり関数から受け取ったりしながら、プログラミング言語の記法(ifやfor)でアルゴリズムを書いていくだけです。そこで行われる全ての機能は、用意された仕組みと提供されたインターフェースを使います。
また、コンピュータはどこまで行ってもブラックボックスです。PHPの命令を記述していても、PHPの関数や記法を「使う」だけに終始し、「仕組みを知る」ことがたとえオープンソースだから出来たとしても、「自分で作る」のは現実的ではありません。
ですが、if文やfor/while文のような基本的な要素を上手く使うことで、「関数や命令をもっと高度に利用する」ということはできます。エラー処理を行ったり、関数を呼び出したり、フレームワークを作って使ったりすることができます。現代的な言語では、クロージャを使ったり、デザインパターンのような設計をすることができます。
また、オブジェクト指向のプログラミングは、あるひとつの「個性」のあるプログラミングが行なえます。たとえば、ゲームを作るのであれば、キャラクターそれぞれに必要なデータ属性はインスタンスとして持っておいて、制御はそれぞれのイベントに対するメソッドやプロパティとして実装し、場面場面でそのキャラクターを作成・起動して実行することができます。オブジェクト指向はとても便利で作りやすい考え方です。
Cだけではなく、VB.NETなどで開発する際も、ポインタや参照型を上手く使うことで、「関数としてこの部分の処理を抜き出したい」という時に役に立ちます。たとえば、ある変数を「変更可能」なままで関数に渡したいときなどに、Cならばポインタ、VBならばByRefなどの方式で渡すことで、簡単にコードブロックを関数にすることができます。
Lispのような関数型プログラミングは、プログラミングでは特殊な方に分類されるかもしれません。純粋に関数としてプログラムを実行することで、全てを式として扱い、ラムダ式・無名関数や再帰のような形でプログラミングが行なえます。ある意味、数式の展開を書いていく感じになります。

プログラミングの初歩

関数の分け方

main関数からコードを書き始めて、関数を分けていくだけでも、プログラミングは出来ます。
最小限の処理をきちんと行う関数を作って、それの組み合わせとして行くだけで、きちんとしたプログラムは書けます。
ただ単にブロックを分けるだけではなく、繰り返しの中を関数にしたり、条件分岐を関数にしたりすることで、プログラミングはスマートに出来るはずです。

ポインタは参照型として使おう

ポインタは、引数の中から外側の世界を操作するような、参照型として使いましょう。
最初のうちは、動的なメモリ管理なんか、必要ありません。

集中化とアクセス許可

プログラミングの良い点は、一人だけで技術やアーキテクチャを作ることが出来る、という点だ。
一人では出来ないと思うかもしれないが、gtkmmなんか6人で開発している。それくらいのメンバーは、OSSプロジェクトに参加すれば、居る。
プログラミングの基本は2つ。
1.まず、関数などによって、集中化、共有、再利用、ラベル付けを行うこと。
2.次に、必要なものや許可を与えるものに対して、どのようにリソースを配置していくか、ということだ。
本当は、プロセスや処理を抽象化する、と言うのももちろんある。だが、基本的には集中化とアクセス許可だ。
プログラムは基本的に、関数と変数と手順を書いた実行の自動処理だ。そこが分かっていれば、出来る。
「ファイルを開く機能」や「表示する機能」を作るためには、それぞれの関数をどう作っていくか、良く考える必要があります。

人間が考えるのと同じように書く

コンピュータは電子頭脳です。プログラムを書く、ということは、人間が考えるのと同じようにコードを書く、ということに他なりません。
人間が考えるのと、同じように書いてください。変数や構造化プログラミングを使いながら、人間が考えるのと同じようにプログラムを作っていきましょう。

変数への値の格納と関数の呼び出しを上手く使う

変数はメモリの中の値の格納場所です。計算したり、関数を呼び出したりした結果の値を格納します。プログラミングでは、変数と関数の呼び出しを組み合わせて使います。
まずは、変数への値の格納と関数の呼び出しを、四則演算や配列のような発想でコードを書いてはいかがでしょうか。
if文(条件分岐)やfor文(繰り返し)は、ある意味「サブルーチン」の一種だと考えられます。
関数を作る時は、引数と返り値を良く考えて作ることで、「さまざまな利用目的によって呼び出される、汎用的な処理」を作ることができます。この時、引数にポインタを使うことで、関数の内部から外部の情報を操作できます。これは、サブルーチンを繰り返し実行するように処理を書く上で、とても有効で、便利です。たとえば、お札の枚数を数えるプログラムであれば、カウント途中の残りの金額を関数の内部から書き換える必要があります。こういう時に、ポインタを使いましょう。これを「値渡しではなく、参照渡しをする」と言います。

データ構造の共有

C言語では、関数と関数外とのやり取りの中で、構造体のポインタを使って共通のデータにアクセスすることが多いですが、これは一種の「データ構造の共有」だと考えられます。
ある種の、関数の内部と外部のやり取りを行うための、「インターフェース」の一種であると考えることもできます。
これは、オブジェクト指向のクラスとインスタンス変数や、JavaScriptクロージャやスコープチェインと同様の考え方です。それぞれの関数の内部から、共通のデータ構造を参照することができます。
C/C++では、関数のインターフェースAPIを提供するためにプロトタイプ宣言とヘッダファイルのインクルードを行いますが、これは「コンパイル時間が無駄に長くなる」として一部では批判されています。このような場合、C2やD言語のような「Cの後継を目指している言語」で改善が図られています。
旧来のプログラミング設計では、まずデータ構造を設計し、その上でアルゴリズムたる「コード設計」を行います。Windowsプログラミングを行う上でも、どんな機能が必要になるかを明確に分析して、共通のデータや情報が必要なところでは、共通のデータ構造にそれぞれのモジュールが参照できるようにしましょう。

関数の分割と分散処理

僕は、プログラミングとしてコードを書くコツは、「どの関数からでも処理を実行出来る」というところにあるのではないかと思う。
たとえば、ファイルシステムへのアクセスやネットワークの接続は、main関数に流れるように書くこともできるが、多くの場合、それぞれの関数に処理を分けて、さまざまな関数を実行した時に実行する。
そのようにすることで、関数を「汎用的な処理」として使うだけではなく、「さまざまな部分に処理を分割(分散)させる」ということができる。
要するに、言ってしまえば「それぞれの機能を単純に関数として作って、引数を渡しながらそれらの関数を操作する」だけで、プログラミングは出来るのである。
ただし、僕が言いたいのは、単に関数を分割できる、ということではない。プログラムが順番通り動いて文字列を出力しているように見えて、実際はありえない関数のさまざまな場所から文字列を出力している。それは、ファイルシステムやネットワークでも同じで、あらゆるブロックからプログラムは関数を呼び出して操作する、ということを言いたいのである。それが、プログラミングのコツではないかと思う。

文字列の操作、ウィンドウの描画、CGI、ライブラリ

プログラミングの機能的な基本として言えるのは、昔のコマンドラインのプログラムは、ほとんどがテキストと文字列の編集や操作の処理であり、たまに条件分岐や繰り返し処理をしながら、計算したりすることがあるだけです。ですが、それを使って高度な(たとえばgitのような)システムを作ります。
GUIが標準的になった現代のプログラミングでは、ウィンドウの操作を中心に行います。ここで行われるのは、イベント駆動のプログラムです。どんなイベントに応じてどのような操作や処理を行うか、ウィンドウアプリケーションではそれがほとんどのプログラミングになります。
それ以外に存在するのは、ファイルの読み書きや削除・名前変更・一覧の取得などの「ファイルシステム処理」と、テキストを正規表現でマッチングさせる「パターンマッチング」や、あるいは、ネットワーク通信の処理です。ですが、ネットワークについて言えば、わざわざソケットを作ってクライアントとサーバーが通信する処理を書くことは少なく、多くはCGIのようにApacheのようなサーバーと連携させながら、HTMLを吐き出す処理を行います。他にあるのは、データベースの処理などがあるでしょう。それくらいで、あとは変数の格納や配列など、基本的な「一時的な記憶」を行う処理が多いでしょう。文法を学んだ後で、そうした基本的なライブラリをマニュアルの記述を参考に参照してください。それで、誰でも、JavaRubyで何でもできるようになるでしょう。何を作ったら良いか分からない人は、Rubyのgemsのような汎用的なライブラリを、自分で工夫して開発すると良いでしょう。ライブラリが大量に多いのはそういう理由だと思います。
文字列の操作をプログラムから行う上で、日本人が直面する問題は、文字コードの問題でしょう。C/C++だけではなく、Apache/PHP/MySQLなどを使う上で、「文字コードとどのようにつき合うか」は日本のLinuxハッカーの永遠の課題です。ですが、最近はほとんどの場合、UTF-8を使えばなんとかなります。C/C++でマルチバイト文字を扱うのがとても不安だという方は、Java/.NETやRubyのような言語を使うと何とかなるでしょう。逆に、Pythonのように「きちんと文字コードを指定しないと日本語が使えない」プログラミング言語もあります。永遠の日本人の「躊躇と戸惑い」が文字コードだと思います。日本人をテキスト・文字列処理ハッカーの道から遠ざけている原因ではないかと思います。

何を目的に、どのように実行されるのか

プログラミングにおいて、関数やコードブロックを構築していく際に考えられるポイントがいくつかあります。それは、「実行し、保管し、渡し、得る」ということです。
1.どのように実行するか。関数を呼び出したり、クラスをインスタンスにしてメソッドを実行する。
2.どのようにデータを保管するか。変数に記録したり、計算したりする。
3.どのように渡し、どのように得るか。関数の呼び出しの時に変数を渡したり、逆に関数の呼び出しから変数を取得する。
そして、この上で、関数全体を設計します。その時必要なのは、
4.どのように実行されることを意図しているか。関数がいつ、どのように実行され、どんな結果を返すように関数を記述するか。
5.どんな機能を目的にそれぞれの関数に役割を与えるか。ファイルシステムなら、書き込み、読み込み、エラー処理などを、どのように作り上げるのか。どのようにそれぞれの関数がプログラムとして作られるのか。
そうした結果できるのが、巨大な関数たちの「関数の集団」です。これをどのように実行するのか、もっと言えばどのように実行されることを意図して作るのか、それによって何ができるのか、そもそもそれは何をしているのか、を考えます。
つまり、「関数で何をするのか」と、「どこでどのようにその関数を使うのか」を考えれば、もう、プログラミングはできたも同然です。あとは、必要なことを、ただ記述していけば、それが単純にプログラムになるでしょう。

ハードウェアを操作する演算計算機

言ってしまえば、パソコンというのは「ハードウェアを操作する演算計算機」に過ぎない。
ここで、「演算計算機」とは、「演算の順次実行と、記憶と、いくらかのジャンプや分岐を行う計算機」ということである。
カーネルも、X11も、ハードウェアと演算を繰り返しているだけにすぎない。仮想CPUや仮想メモリは、スケジューラや仮想アドレス空間やページによって行うが、これは「演算をただしやすくしているだけ」に過ぎない。
UNIXだけではなくWindowsについても同じで、ハードウェアの処理と演算を交互に繰り返しているだけに過ぎない。OSはそんなに大したプログラムではない。

課題を作ること

プログラミング能力の向上に必要なのは、「課題を作ること」です。
僕はデザイナー見習いとしてデザインの勉強と仕事をしていますが、毎日のようにIllustratorに触れながら、実際のデザインの仕事をすることで、Adobe製品の使い方を知り、どのようにすればできるのかを学びました。
この「実際に取り組むこと」は、プログラミングにおいても変わりません。実際に、「課題を作ること」で、プログラミング能力は向上します。
どんなに本を読んでも、どんなに勉強しても、実際に課題を作り、その課題をこなして実現させること以上に、近道は存在しません。
課題となるプログラムを1つ決め、それを作るために全ての情報を処理して頑張ってください。プログラマーになる一番の正しい道は、課題を作ることです。

プログラムの基本はデータ処理と表示

プログラムの基本は、データ処理と表示です。
データを読み書きし、出力を表示し、場合によってコマンドやフォームから入力を得ることで、プログラムは成り立ちます。
たとえば、CGIのゲームであれば、まずキャラクターのデータを読み込み、戦闘相手である敵とキャラクターとのバトルを繰り返し表示し、勝利か敗北かの出力を表示し、キャラクターのデータを保存します。
バトル画面だけではなく、アイテムの購入や装備品の変更画面でも、まず金銭状況や既に持っている武器の情報をデータから読み込み、プレイヤーの選択をフォームでやり取りし、購入確認画面へと進んで、所持品や金銭状況のデータを保存します。
ゲームだけではなく、チャットや掲示板のCGIプログラムでも同じです。CGIだけではなく、コマンドプログラムやGUIのアプリケーションでも、基本は「データの読み書きと入出力」です。
基本はそれに尽きると思いますが、さまざまな媒体やプラットフォームによって違いが生じます。以下はその一覧です。

  • コマンド
    • コマンドラインオプションなどで引数を取得し、printf, fgetsなどで文字列の入出力を行う。
  • ファイルシステム
    • open, close, read, writeでデータを読み書きする。
  • スクリーンエディタ(viなど)
    • 端末のスクリーン全体に文字を表示し、マルチラインで文字列を操作し、コマンドで保存する。
  • HTML/CGI
    • HTMLタグで出力を表示し、GET(URLパラメータ)とPOST(テキストボックスやボタンなどのフォーム)でユーザーとデータをやり取りする。
    • Perlなどの構文でファイルを読み書きする。
  • SQL
    • SELECT, INSERT, UPDATE, DELETEなどのSQL文でデータを抽出・挿入する。
  • GUIWindows APIなど)
    • GUI画面でラベルやテキストボックスにデータを表示し、メニューやボタンでユーザーとデータをやり取りする。
    • 編集中のデータはコントロール操作としてインタラクティブに操作できる。
  • MFC(ドキュメント・ビュー)
    • DocumentクラスとViewクラスで読み書きと表示を行う。
  • MVCフレームワーク
    • モデル・ビュー・コントロールでデータの表示とデータベースでの保管を行う。

ある意味、Bashのようなシェル記法や、JavaPerlのようなプログラミング言語も、こうした「データの読み書きと入出力」の形態の1つと言えるでしょう。
ただし、本当はMozillaのようなネットワーク処理やsedのようなテキストフォーマットの処理、gccのようなコンパイラやgitのようなバージョン管理システムなど、高度なデータ処理・文字列変換システムもたくさんあるので、あらゆるプログラムがこれだけに収まるわけではありません。
ですが、プログラミング初心者のように「何から書いていいか分からない」場合は、データの読み込み、出力の表示、書き込み、そしてフォームの表示によってプログラムが簡単に書ける、というのは、分かっていると有益だと思います。
何も分からない人には、Ruby on Railsをやるのをおすすめします。モデルとビューとコントロールを作ることで、誰でもこうした「データ処理と入出力」がどんなものであるか、ありありと分かるからです。(ただし、Railsだけで終わらないこと。Railsだけで終わってしまうと、Railsしかできない人間になると良く言われています。)
そもそも、コンピュータを「計算機」と呼ぶものの、内部でやっていることの多くは、変数や入出力などの「データ処理」と、関数や制御構造を用いた「手続き」です。データ処理を行い、さまざまなジャンプや変数渡し、条件比較のような「手順通りの実行」を行うこと、そのためのアルゴリズムとデータ構造をきちんと成り立たせることで、プログラムは開発されます。

ライブラリの設計と関数やクラスを覚える

プログラミングを行う上で、知っておくべきなのはライブラリの設計とAPIです。たとえば、GTK+APIを覚えれば、GTK+ウィジェットを使ったLinuxでのGUIプログラミングができます。
これは、たとえば、MS-Officeの使い方を覚えるのと同じです。どんな機能が提供されていて、どのように記述すればどのようなことができるのか、ということをただ覚えれば良いのです。
C/C++だけではなく、Java, PHP, Python, Rubyなど、さまざまな言語やクラスライブラリがあります。コンパイラや言語処理系のコアな振る舞いや原理を分かることも功を奏するでしょう。
そして、本を読むのであれば、初心者向けの本をいくらか読んだ先は、プログラミングPerlのような言語の設計者が書いた本を読めば、何でもできるようになります。「一冊完読すれば一生モノの知識」になるでしょう。僕は最初に知るべきはPerlをおすすめします。その後にJava, Python, Ruby, C#などを学び、最後にC/C++を習得するのが良いでしょう。
ですが、その際に、言語的な記述法については、他の言語と似通った部分はとばして構いません。ライブラリや関数・クラスのAPIのような「違う部分」だけを参照すれば、すぐに全ての言語をマスターできるでしょう。

プログラミングは猿に教える芸と同じ

言ってしまえば、プログラミングはサルに教える芸と同じです。「さあ、これをやれ。その次にこれをやれ。そしたら、こういう時はこうしろ。そら!できた。」と、そういう風にプログラム芸を馬鹿な猿コンピュータに仕込むこと、それがプログラミングです。
OSはプログラムを実行するプログラムで、リソースを割り当てるプログラムです。これを猿に喩えると、仮想猿集団に芸を仕込む曲芸師である、と言えるでしょう。そしてこれも猿です。この猿の他の猿と違う点を言えば、「猿に芸を仕込むという内容の芸をしている猿」であると言えるでしょう。
OSには仮想CPUや仮想メモリ機能があって、仮想猿集団はたくさんの猿が居るように見えて、本当はひとつのOSの統括する猿頭脳(ハードウェア)の中で実行されているのです。OSは芸を仕込むためのリソースが必要になると、仮想猿を1つ作ります。この仮想猿が芸をしますが、本当に頑張っているのはOSという猿の頭脳(本当のCPUとメモリ)です。
AIが人間並みの知能を持ったと良く言われますが、これは人間を作り出せたというわけではなく、人間と同じことができるまで猿の芸が進歩したというだけです。
これらの猿は賢いので、人間よりも賢い芸を巧みにこなしますが、芸を考えるのは人間(プログラマ)です。
プログラマがその時その時教えなくても良いように、芸は専用の言語で書かれます。この専用の言語を猿でも分かるような単純な猿語に変換するのがコンパイラです。インタープリタを使うと、猿に直接人間の言葉で話しながら、その時その時猿語に翻訳してくれます。
猿はとても優秀で、なんでもこなすことができ、それは芸だけではなく仕事や芸術、科学技術のようなことも猿が可能とします。だが、唯一、芸(プログラム)を考える猿は今のところ出来ていません 。人間の仕事は、猿に教えるための芸を考えることです。
ログインとログアウトは猿芸を見るためのチケットの確認と入退場です。ネットワークは、もっと大きなボス猿に共同作業を頼むことです。入出力は猿への声援、SSHは猿芸のテレビ中継でしょう。ファイルシステムやデータベースは、猿が芸をする時に必要な芸の子道具や絵(データ)を人間に頼んで用意してもらうことです。
猿と言うわけではなく、ピアノにも喩えられます。テープレコーダーに喩えることもできるでしょう。プログラムは音楽であり、プログラム言語は楽譜であり、ハードウェアはピアノであり、プログラマはピアニストであり、演奏は仕事です。
また、良くプログラマのことを「IT土方」と言う人が居ます。これは、プログラミングの作業というものが、公共インフラである道路やトンネル、水道管やダムなどの開発に似ているからです。どんどん開発し、変数の中を情報が通り抜けるように関数や制御構造を当然のように組んでいく作業は、IT土方そのものです。ですが、本当は、コードを書いている時間よりも、設計やアルゴリズムを考えている時間の方が長く、設計をする際もウォーターフォールなどの開発規則を使って賢くスマートに組んでいきます。ですので、工事現場の作業員というよりは、開発作業を行うお役人のようなものに近いと言えるでしょう。
ある意味、フロントエンドエンジニアは猿の曲芸師で、バックエンドエンジニアはIT土方のインフラ開発作業員であると言えます。

昔は、プログラムとデータは別だった

はるか昔の話ですが、昔のコンピュータは、プログラムを紙テープあるいは配線盤から供給していました。紙テープでは動作が遅く、配線盤は作り直す手間があったため、プログラムはデータとして扱われるようになりました。
そう、昔は、プログラムとデータは別々だったのです。
今のコンピュータの中央処理装置と主記憶装置という関係は、プログラムがデータになったごろに確立しました。1945年ごろの話です。
プログラムがデータになったおかげで、テキストとして機械のロジックを扱うことができるようになりました。高級なプログラミング言語を用いて、コンパイラソースコードから機械語を生成するようになったのは1960~1965年ぐらいの話ですが、このプログラムをデータとして扱う、というところから、今のUNIXのモデルが誕生したと言えるでしょう。OSが一般的になってきたのは1965~1970年ぐらいの話です。そのごろから、マルチプログラミングや仮想記憶などの仕組みを用いるようになりました。
今のOSでは、プログラムは完全にデータです。この、データとして機械のソースコードを扱う、ということは、オープンソースととても相性が良く、UNIXシステムの真価を発揮させています。Gentoo LinuxPortageを使うと良く分かりますが、Linuxにおいて全ての構成要素はテキストやデータから生まれるのです。
注意:UNIXは1969年から1970年代にかけて開発されましたが、一般的に使われるように普及したのは少し後の話です(1980年代)。また、ミニコンと呼ばれる1人が所有するコンピュータや、パソコンと呼ばれている個人向けのコンピュータの歴史もあります。

変数と分岐:静的に変わらないものと動的に変わるもの

プログラムとしてのソースコードは、静的に同じで、変わることがありません。ですが、変数の内容(変数にどんなデータが代入されるのか)や分岐した上で条件などによってどのようにコードが実行されるか(条件によってAの道に行くのか、それともBの道に行くのか)、あるいは条件式を用いた繰り返し(いつまで繰り返しを実行し続けるのか)など、ということは、プログラムが実行するたびに変わります。
プログラマは、ソースコードとしての「静的に変わらない部分」や、データ処理や分岐条件としての「動的に変わる部分」を比較し、上手くバランスを取りながらプログラムを組みます。
たとえば、同じプログラムでも、「Hello, World!」しか出力できないプログラムと、引数として与えた$xを表示するプログラムでは、ソースコードが全く違うものになります。
プログラミングとは、そうした静的かつ動的な場合の変更を支配しながら、どれくらいの場合に対応できるプログラムを書くか、ということなのです。
また、コンパイル時に決まることと、実行時に決まることは、違う場合があります。たとえば、ソースコードをさまざまなプラットフォーム向けに#ifdefでマクロ的に処理するのはコンパイル時に決まりますが、ファイルを読み込んだりコマンドラインオプションを与えたりするのは実行時に決まります。拡張性豊かなソフトウェアを作りたい場合は、設定ファイルの読み書きやプラグイン機構も考えなければなりません。逆に、そうした動的処理にしないことで、単純な動作を可能にすることもできます。
関数を上手く使うことで、汎用的な自動実行処理を記述することもできます。たとえば、2つの引数を取ってその足した和をreturnで返す関数などを作ることができますし、変数にファイル名などを取って、汎用的なファイル処理を行う「バッチ関数」を作ることもできます。
ブロックや無名関数が使える場合、あるいは抽象クラスの抽象メソッドを継承したり、インターフェースを実装したりする場合などは、「後で誰かが勝手に動作を変えられるようなプログラム」を書くこともできるでしょう。動的なメモリ管理も、こうした分野に含まれます。特に、どれくらいの大きさの配列を用意すれば良いか分からない場合は、mallocを使ってヒープ領域に配列のデータを確保します。リストのようなデータ構造を使って、配列ではない形でコンテナを作ったり、イテレータでコンテナを処理したりすることもできます。
これらは全て、「静的に変わらないものと動的に変わるもの」という考え方であると言えるでしょう。そして、プログラミング言語の提供する多くのことは、静的・動的な動作を「どれくらいプログラマブルにするか」ということに尽きるでしょう。ライブラリAPIや、テンプレートやジェネリックを使うことで、もっと動的に、もっと変化可能で汎用的なプログラムを作れるでしょう。

基本はあくまでも計算

プログラミングはアプリケーションの設計ですが、プラクティスばかりに気をとられるのではなく、「基本はあくまでも計算」であると言うことを忘れないようにしましょう。
たとえば、ソートやリストのような設計についてそれが言えます。
プログラミングとは、「計算していく手順を書く」ものです。よって、計算が表現できれば、それできちんとアプリケーションの設計が出来ます。
この時、関数やクラスの設計も、同様に「計算」であると考えましょう。C/C++を使っていると、ありえないほど覚えることがたくさんありますが、基本は計算です。クラスは計算するための「要素を記述」することです。クラスにおいてメンバ変数とメンバ関数を上手く設計するために必要なことは、「どのように計算すればプログラムとして成り立つか」ということに他ならないのです。
オブジェクト指向でプログラミングを行う上で優れた点が、「メンバ変数の共有とメソッドの継承」です。これによって、複雑なプログラムであってもC++Javaで動くコードに直すことができます。あるいは、インターフェースの実装などに見られるように、「別の人が作ったクラスでも、他の誰かが既に作ったものと同じように操作出来る」ということは功を為すことがあります。C++Javaはあくまで計算を助けてくれるだけです。実際に計算手順を書くのは、プログラマという人間が行ないます。
また、関数やメソッドの設計は、「与えられた情報からどんな処理を行うかを決める」という点で、「情報」であると言えます。これは、プログラミングの全てに言えることで、「どこにデータを保管し、どこにデータを(整形などして)表示するか」ということが、CUIでもGUIでも言えます。この時、どのようにオブジェクト同士のやりとりを行うのか、どのようにオブジェクトを作成・破棄・追加・削除するのか、ということがプログラミングの課題になります。プログラムの中では、データを常にどこかに保持しながら、たくさんのオブジェクトを作成・破棄するのです。そして、そのオブジェクトが関係性を持って、オブジェクトを別のオブジェクトが操作し、オブジェクト指向プログラミングは成り立つのです。
フロントエンド的な関係性だけではなく、目的を持ってバックエンドも作りましょう。ここで言えることは、「どれくらいのレベルでのコンポーネントを目指すのか」です。多機能を目指すのか、高速・軽量を目指すのかで、仕様と実装は変わってきます。良い例として、2ちゃんねる専用ブラウザのOpenJane Doeがあります。これはあえてIEコンポーネントを使わず独自の軽量なビューを実装することで、高速かつ軽量な2ちゃんねるブラウザを実現しました。そのように、「どれくらいの機能レベルを目指すのか」が、バックエンドの開発の基本となるでしょう。
あとは、概念と方法を考えます。UNIXファイルシステムの実装として必要なのは何か。それから、インターネットからファイルをダウンロードして表示させるために、必要な概念は何か。概念が分かったら、どのようにすればそれを実現させることができるか。方法として何が考えられるか。そして、どれくらいのレベルでそれを実装するか。そこまで考えて、書けばおそらく、目的のプログラムが見えてくるでしょう。
計算のクラス化は難しいように見えるかもしれませんが、やるべきことは単純です。必要な情報をデータとして保持するようにデータ化し、必要な処理をメソッドにし、場合やイベントに応じて実行すれば良いのです。FTPクライアントなど、決まった処理を実行するプログラムであれば、それだけで大部分は作れるでしょう。難しいのは、高度な計算が必要なデータベースやコンパイラですが、これも、1つ1つの必要な機能を細分化し、部品化し、その部品と部品を繋ぐように作っていけば、きっと作れるはずです。
プログラミングの基本は、「必要なたくさんの処理を、簡単にできるようにすること」です。たとえば、文字列の解析を行うのであれば、文字列の解析をする部分であるparse()関数を作って、解析を行いますが、この中で必要な処理の全てを書いて、parse(bytecode, in)と記述したら、簡単にinをbytecodeにパースできるようにします。これが、プログラミングの基本です。たくさんの処理を1つの関数にして、その関数を使うことで何度でも簡単に同じ処理を行えるようにする。あとは、ただそうした関数群を作ります。たとえば、bytecodeをアセンブリ言語に変換するconvert()関数を作り、convert(out, bytecode)などとします。ここで、parse()関数とconvert()関数の中で、変数定義をmvに変換するvar_convert()関数、if文やfor文や関数定義を機械語に変換するif_convert(), for_convert(), func_convert()などを作りましょう。実際のコンパイラの開発では、トークンの解析にはlexやyaccを使い、三番地コードと呼ばれる形式のコードに変換していきます。この中で、きちんと定義する必要があるのは、中間コードであるbytecodeオブジェクトをどのような形式のデータ構造にするか、といったことになるでしょう。
自分は、経験も無いのに適当なことを言ったかもしれませんが、このように作っていくのをプログラミングの作業だと思えば良いでしょう。データベースやUNIXファイルシステムでは、「排他制御」を行う必要があるでしょう。これは、あるデータ構造を持ったデータが操作中の時、その間別の人間から操作できないようにすることです。そして、ファイルシステムであれば、ファイルを識別するiノードやデータ自体を格納するブロックをどのように保管するかが重要になります。この場合は、関数をただ作るというよりも、設計をどのようにして、どんなアーキテクチャで実現していくか、ということが重要になるでしょう。ディスクにファイルアロケーションテーブル(FAT)とセクタごとのデータを書かなければなりません。

テキスト処理を極める

やっぱり、プログラミングの基本はテキスト処理だと思います。グラフィックやネットワークに比べて面白くないかもしれませんが、テキスト処理を極めるところから、プログラム開発を始めましょう。
また、科学技術計算とゲームは、馬鹿にしてはいけません。それらが本来のプログラミングだからです。
テキスト処理を極めてください。そして、科学技術計算とゲームを作っていれば、それで正しいプログラマです。

オブジェクトの作成はアプリケーションの起動と同じ

オブジェクト指向をやる上で、良く分からないのが「クラスをどのように記述し、どのように利用するか」です。
ですが、言ってしまえば、クラスをnew Class()して作成するのは、アプリケーションの起動や実行と良く似ています。
たとえば、ブラウザクラスであるBrowserクラスを作って、ブラウザオブジェクトをブラウザクラスからnew Browser()してインスタンスを作成するのは、ブラウザアイコンをダブルクリックしてブラウザが開くのと良く似ています。
クラスの方で、格納するための変数やその変数を変え、プロパティを取得・設定するためのプロパティやメソッドを作るのは、アプリケーションであるブラウザに設定画面から設定するのと同じです。
そのように考えれば、オブジェクト指向でクラスを設計する、ということが、ブラウザのような巨大アプリケーションの設計と同じである、ということが分かります。つまり、プログラムの集合体として、全体の巨大なプログラムを開発する、ということです。クラスとはプログラムの部品です。インスタンスの作成は、プロセスの作成と全く同じなのです。
そういうわけで、クラスの設計は専門別のアプリケーションを作るという風に考えてすればできる。だが、デザインパターンのようなものもあるし、設計にはさまざまな技術的要素があるので、一概には言えない。たとえば、PHPであればデータベースの管理を行うクラスを作ったり、ビューを管理したり、index.phpから全てのPHPプログラムに橋渡しをしたり、と言った具合である。

巨大で動かないものよりもシンプルで動くものを

初心者がプログラミングでやりがちなこととして、「最初から優れた仕様を作りたがる」というのがあります。
最初からアイデアばかりが先行して、自分の技術がそれに見合わず、結果巨大な仕様をいきなり実装しようとして、バグだらけで動かないものになって、そこで終わりになるのです。
MulticsHurdのような経験から言って、最初から巨大な仕様や賢い仕様を求めて作ろうとすると、結果プログラムは動かないものになります。
では、どうすれば良いか。まず、最初はシンプルなものを目指しましょう。ただ動けばそれで良く、動くことだけを重視して、システム全体をシンプルにし、相互依存や強い結合をせず、疎結合のシステムを作りましょう。
そして、動いたらそれに満足して、とりあえずそこで終わりにします。あとの改良点は、少しずつ、全体のバランスを崩さないように、慎重に行います。ですが、プログラムが巨大になってきたら、分割して、それぞれの部分でテストを行ったり、少しずつ関数を増やすことで機能を増やしていきます。
シンプルなシステムほど優れたシステムはありません。UNIXが古びているのに今も使われるのは、シンプルできちんと動くからです。それ以上の理由はありません。
リーナス・トーバルズが好まれる理由もそこにあって、最初は単なるターミナルエミュレータを作っただけだったものの、Minixを改良するうちに、改良したコードだけで動くようになりました。最初はとてもシンプルなカーネルだったものを、みんなで改良しました。ですが、みんなで改良しただけでは、Linuxカーネルは生まれなかったでしょう。リーナスが何を作るべきで何を取り入れるべきか、きちんと考えて少しずつ改良した結果がLinuxです。そこが良かったから、みんなリーナスが好きです。IBMが嫌われるのは、最初からドンと大きなものを提示するからです。Microsoftも同じで、Appleも同じです。最初から大きなものを作っても、支持は得られません。Googleはそういうところがやり方がうまいのでしょう。GNOME3やKDEも、同じ理由で全く使われません。最初はXfceのような小さなソフトから作らなければいけないのです。

どこまでを静的に、どこまでを動的に決めるのか、いつ決まるのか

僕は、プログラミングにおける大部分とは、どこまでを静的にするのか、どこまでを動的にするのか、そしてそれがいつ決まるのか、ということだと思います。
たとえば、
・プログラムに直接書く
・変数に代入する
・ポインタとmallocで記憶領域を動的に作成する
・引数に渡す
・returnで戻り値に返す
・ポインタで共通の構造体データを操作する
オブジェクト指向を使う
コンパイルオプションで変わるマクロを記述する
・実行オプションを渡す
・設定ファイルを読み込む
・関数を別のプログラムからライブラリ関数・APIとして呼び出すように設計する
・CORBAのような分散コンポーネント技術を使う
LispPythonXULのようなプラグインや拡張によって、プログラム自体を拡張する
ソースコードそのものを書き換える
・継承によって、元のプログラムはそのまま残したまま、新しい機能を追加する
など、さまざまな方法で、どこまでを静的にするのか、どこまでを動的にするのか、それらがいつ決まるのか、ということがプログラム設計の巨大な柱となります。
それに、プログラムを記述する上で、どこまでを意図して汎用的にするのかは、関数の汎用性を高めます。
また、これと良く似た意味で、「移植性」が存在します。どこまでをそのプラットフォーム固有のものにするのか、それともさまざまなシステムに広く対応できるようにするのかは、UNIXJavaなどにおける大きな課題でありました。
基本的に、動的にすればするほど汎用性は上がり、使うのも作るのも楽になりますが、バグの混入する恐れが強くなります。逆に、静的にするとシンプルにはなりますが、逆に動かないことやメモリリークが発生することも多くなり、「細かな管理技法」が必要になります。

ポインタは変数のアドレスを使ったアクセスの手法

C言語で使われるポインタは、変数のアドレスを使ったアクセスの手法です。
ポインタを使わずに変数を宣言した場合、宣言するごとに別の領域に変数ができます。
これに対して、ポインタを使うことで、変数は「アドレス」を指定してアクセスすることができます。
xとyとzを普通に宣言すると、それぞれに別の領域ができますが、yやzという名前でもxと同じアドレスを参照したい場合に、ポインタを使うことができます。

制御フロー

制御構造とフローチャート

ifやforなどの「条件分岐」と「繰り返し」は、その時その時の場合によってプログラムが何を実行し、何を実行しないか、どれだけ実行し続けるか、を条件的に記述します。
変数が何を持っているか、条件式が何を判断しているか、実行するか実行しないかの範囲と内容は何か、いつどのように実行されるか、いつどのように実行されないか、などを考えると良い。
紙にフローチャートを書いて練習すると良いでしょう。

条件式に応じたプログラミング

ここで重要なのは、「条件式」です。条件式に応じて、条件が満たされる間繰り返し処理を実行したり、分岐して別々のコードブロックを実行したり、変数に別の値を代入したりします。
当然のことながら、条件式が間違っていた場合は、プログラムは正しく動きません。
条件によって別の関数を実行する関数のように、「ラッパー的な関数」を作ることもあります。
また、ゲームであれば、ランダムな数値を変数に代入したり、敵が出現するかどうかの判定や、キャラクターの攻撃が当たるかどうかの判定、敵の生死の判定、ターンごとに攻撃に参加できるかどうかの判定などにも、条件式と変数の代入を使います。
データベースやファイルシステムであれば、データの一意の識別のためにキーとなるIDナンバーやiノードなどを代入して、条件ごとにコードブロックや関数を実行します。
また、代入されている変数の値に応じて、別々の処理や制御を行うこともあります。
先のゲームの判定で言えば、代入されている値に生存が代入されていればゲームを続け、死が代入されていればゲームを終了する、といった具合です。
条件式に応じたプログラミングは、C言語コマンドラインプログラムなどに多くみられます。

イベント駆動によるプログラミング

条件式以外の制御フローとしては、イベント駆動などが考えられます。
たとえばゲームであれば、キャラクターがジャンプした時、どれくらいキャラクターが上に飛び上がるかとか、キャラクターが前方方向に進んだ場合に敵に当たらないか、ステージから落ちないか、画面をスクロールするかどうか、のようなことをイベント駆動で行います。
これはイベントループによって、何らかのイベントが生まれるまで待機し、何らかのプレイヤーの操作が行われたらそれに応じた処理や判定をして画面を再描画する、といった具合で実現できます。
イベント駆動によるプログラミングは、UNIXカーネルや、GUIのプログラム、ネットワークサーバーなどに多くみられます。特にGUIではメッセージループとイベント駆動により、ツールキットフレームワークを使ったプログラム開発を行うため、CUIのプログラムよりも冗長で複雑かつ、プラットフォーム依存のプログラムになります。

抽象的な基盤システムの構築

また、プログラムを作る上で重要な考え方が、「抽象的な基盤システムの構築」です。
たとえば、ゲームを作るのであれば、ひとつひとつの対戦画面を作るのではなく、ひとつの「共通の対戦を行うための画面」を作って、そこに具体的なデータを流し込んで、戦闘画面を作ります。
そのため、ピカチュウカイリューが戦うのであっても、ニドキングが戦うのであっても、作るべきなのは、ひとつの「対戦画面」です。
マップ画面やダンジョン画面も同じです。ひとつひとつのダンジョンを一から作るのではなく、「共通のマップ画面」を作り、そこにキャラクターの「ドットイメージ」をマスの中に表示していきます。
どんなゲームであっても、これは変わりません。カードゲームなら、盤面の画面をひとつ作ります。3D対戦ゲームなら、3D画面を作ります。また、シミレーションRPGであっても、マップを移動するそれぞれの「駒」を適切に表示するような画面を作ります。

繰り返しを使ったプログラム

プログラム初心者が忘れがちなこととして、「繰り返しの回数も数である」というのがある。
たとえば、10という数字が与えられて、10回繰り返しの中の文を繰り返すプログラムというのがこれである。
プログラミングとは、「その数から何をするか」という「文の実行順序・実行回数」を書く作業である。このため、回数も数である、ということは大切である。
また、繰り返しには条件式を使ったり、あるいはbreak文が実行されるまで永遠に繰り返したりなど、「繰り返しを終える条件」というのも必要である。
たとえば、味方の全キャラクターが死ぬか、敵の全キャラクターが死ぬまで、互いにキャラクター一人ずつが互いに攻撃する、といったゲームがこうしたプログラムである。

正規表現を使ったプログラム

また、繰り返しと良く似ているのが、正規表現を用いた文字列をパターンマッチングさせるプログラム。
たとえば、HTMLをTeX文書に変換するスクリプトなどがこれである。
HTMLをTeXにコンバートするためには、それぞれのタグをTeXのマクロに変換する必要がある。
たとえば、
1.コメント部分(<!--~-->)を削除する。(これだけでも、きちんと作るのは大変)
2.<body>から</body>までを切り出す。
3.切り出した内容について、<script>~</script>を削除する。
4.<h1>~</h1>などをsectionやsubsectionなどに変換する。
5.それぞれのタグ(<li>など)を適切にTeXのマクロに変換する。
6.必要のないタグ(<p>など)を削除する。
7.最後に、TeXの適切な記述をヘッダ部分とフッタ部分に追記する。
このようになる。実用性を考えるならば既にあるコンバートツールを使うか、手動でテキストエディタで検索・置換を繰り返した方が良いだろうが、プログラミングの勉強としては最適である。

関数は自動の実行処理

また、関数は自動の実行処理です。ある引数に基づいて、どのような処理を行うかが、汎用的に記述され、汎用的に実行されます。
引数とreturnを上手く使いましょう。また、再帰を使うことも良くあります。再帰とは「その関数の中でその関数を呼び出すこと」です。
後日注記:言ってしまえば、定型の処理をあらかじめ記述しておいて、そこにどんな引数が来ても良いようにプログラムを記述し、さまざまな引数によって呼び出して実行し、その結果となる返り値を返す、これが関数の基本です。そのため、自動の実行処理と言えます。

サブルーチンはサブのルーチン

また、サブルーチンはサブのルーチンだと思えば良く分かります。「メインのルーチン」があったとして、そこに「サブのルーチン」を作り、メインからサブを呼び出すのです。
ひとつの処理の流れがあったとして、関数やサブルーチンにはそのメイン処理とは別の処理の流れがあります。
メインルーチンからさまざまなサブルーチンに移動することでプログラムは動きます。つまり、「メインのプログラムとは別個にあるサブのプログラム」があり、「プログラムが別のプログラムを呼び出す」ような形で全体のプログラムを作ることで、構造化プログラミングは成り立ちます。

小規模プロジェクトと大規模プロジェクト

プログラムには、小規模プロジェクトと大規模プロジェクトがあります。
小規模プロジェクトは、たとえば簡単なUNIXコマンドや、掲示スクリプトなどです。こうした小規模のプログラムは、ひとつのファイルで正しく制御フローを記述します。関数もいくらかしかありません。
これに比べて、大規模なプロジェクトは、LinuxカーネルNetBSDカーネル、あるいはApache httpdサーバなどです。こうした大規模なプログラムは、ディレクトリを大きなサブディレクトリ階層構造に正しい規則で分類し、ソースファイルは関数だけではなくライブラリやコンポーネント機構を使ってモジュール化していきます。
また、小規模でも大規模でもない、普通ぐらいの規模のプログラムというものも存在します。これはIEコンポーネントを用いたタブブラウザや、テキストエディタなどです。
どんなプログラムを作るのであっても、まずは小さなプロトタイプの開発から始めます。データ型や汎用的な関数は開発の途中段階で開発します。また、リファクタリングとテストを行い、ひとつひとつソースファイルを整理していきます。同時に、保守がしづらくならないように、分類の方法、分化の方法を考えながら開発を行います。
もちろん、動くためのアルゴリズムアーキテクチャも考えなければなりません。中心となるアルゴリズムを、どのような設計と実装で実行するように作るかが鍵となります。

プログラミングとは手続きの記述

また、プログラミングとは「手続き」の記述であると考えられます。
これは、ハードウェアに近い処理で言えます。特に顕著なのがネットワーク処理(ネットワーキング)です。ネットワークでは、ソケットインターフェースを使って、手続きそのもののプログラミングを行います。多くのコードが、形式的な手続きの記述になります。

パソコンはテキストの動く機械

また、現代的なコンピュータは、「テキストの動く機械」であると考えられます。
この「テキスト」とは、プログラムの書かれたソースコード、設定ファイルや設定データベース、そしてデータファイルやログファイルなどが言えます。
UNIXのプログラムは、プログラムのソースコードとバイナリファイル、設定ファイル、データファイルがセットになっています。プログラムが設定とデータを読み込んでプログラムの動作が決定されます。場合によっては、コマンドの実行オプションや引数、そしてプログラムをコンパイルする時のビルドオプションまでが、プログラムの動作を決定すると考えることができます。ほかにも、モジュールや拡張機能などで、プログラムをカスタマイズできます。ソースコードを直接編集しなくても、オブジェクト指向の機能やマクロ言語などの機能を用いて、プログラムをカスタマイズすることができることもあります。
この「テキストが動く機械」という発想は、Gentoo Linuxをやると良く分かります。Gentooでは、Portageと呼ばれるソースベースのパッケージ管理システムを使うことで、プログラムをコマンドに応じて自動でダウンロード・ビルド・インストールできます。まさに「Linuxがどのように形作られるのか」を、コンパイルやインストールなどの出力を「自分の目で見る」ことで知ることができます。また、Gentooでは設定を自分で設定ファイルに手動で書くことによって行いますが、これにより、「自分で設定した内容を自分で見て設定する」ことができます。インストーラもありませんが、ローリングリリースを採用しており、一度インストールしたら二度同じことをする必要はありません。

エラー処理と例外

C言語では、ファイルのオープンの際、ファイルがきちんと存在し、読み書き権限が得られ、オープンに成功した時と、そうでない時を区別し、エラーが発生した時のためにエラー処理をしなければなりません。
これに対して、C++Javaなどのオブジェクト指向言語では、「例外」を用いてエラー処理を行うことができます。例外が吐かれると、その時点でコードの実行をやめ、「キャッチブロック」と呼ばれるブロックにキャッチされて、そのエラーを処理することができます。

関数は呼び出し方を想定しながら、共通の処理をひとつにまとめるように作る

また、関数を作る時のコツとして、「呼び出し方」を考えながら、「共通の処理をひとつにまとめる」ように作ります。
関数の呼び出し方は、たとえば引数に2つのint型の数値を取って、int型の返り値を返す、といった具合です。
共通の処理をひとつにまとめるとは、たとえばお札の数を数える時に、ひとつひとつのお札の条件比較をする処理を、ひとつのルーチンにまとめる場合などが考えられます。
ここで、ポインタが活躍します。というのも、共通の処理をひとつにまとめる上で、どうしても引数を関数の中から参照だけではなく変更したい場合があるからです。
ポインタだけではなく、グローバル変数オブジェクト指向のクラスとオブジェクトを使うことで、「たくさんの関数の中でどのようにデータを保持し、共有してアクセスするか」を考えなければいけないこともあります。関数の外側にある、関数を呼び出した元のローカル変数にアクセスしたい場合は、やはりポインタが活躍するでしょう。

関数いろいろ

関数について他には、Windows APIVisual Basicのようなイベント駆動の考え方を用いて、「コールバック関数」のように使う方法があります。
これは、既にあるシステムから自分の作った関数を登録して「自動で適切に実行されるようにする」という考え方です。
JavaScriptでも、HTMLのタグの中でJavaScriptの関数を呼び出すことで、「クリックされたらこの関数を実行する」といった具合にすることができます。
また、Pythonなどでは、関数型プログラミングの考え方で、mapなどに関数を渡して、「関数そのものを関数の引数として渡す」といったことができます。C言語では、関数ポインタを使うことで同じことができます。
また、関数について他に言うと、オブジェクト指向ライクな考え方として、「特定のデータ構造を操作する一連の関数を用意して、その関数からデータ構造を操作する」という発想があります。オブジェクト指向では、こうした関数をメソッドと呼び、データ構造とメソッドが一体化したものをクラスと言い、オブジェクトを作成し特定のインターフェースから操作することをカプセル化と言います。
また、オブジェクト指向と似た考え方として、「関数のスコープと同じ場所にある変数に関数の内部からアクセスする」という方法があります。これを「クロージャ」と呼びます。クロージャにより、スクリプトライクに共通のデータをさまざまな関数から操作できます。

データ操作

変数には、一時的な記憶領域と、関数の間で共有されるデータ構造がある

僕は、変数には二種類の使われ方があると思います。
1.一時的な記憶領域。コードブロックの中で、ローカル変数として宣言される。
2.各関数の間で共有されるデータ構造。グローバル変数あるいは引数での構造体のポインタとして定義される。あるいはオブジェクト指向ではクラスやオブジェクトのメンバ変数がこれに相当する。
この2種類は、「スコープが消えても残り続けるかどうか」という違いがある。ローカル変数はスコープから抜ければ消え去る。構造体のポインタはスコープが消えても残り続ける。
C言語でも、C++などのオブジェクト指向言語でも、この2種類があります。これを分かっておくことで、Linuxカーネルなどのコードを理解しやすくなります。
また、もう一つのやり方があるとしたら、
3.関数の呼び出し元と呼び出し先の間でやり取りされる変数。引数や返り値あるいは戻り値と呼ばれる。
があるでしょう。

外部に状態を設定ファイル・データファイルとして保存する

プログラム、特にゲームのようなプログラムに言えることとして、外部に設定ファイルやデータファイルを作り、キャラクターの状態やゲームの進行状況などを保存する、といったことがあります。
普通にPerl/CGIでプログラムを組んでいると、変数とrand()関数のようなランダム数値だけで、おおざっぱなルーチンは簡単に作れますが、これだと、毎回実行するたびにキャラクターの能力やヒットポイントが最初に戻ってしまいます。
こういう時、Perl/CGIでは外部に設定や状態を保管するデータファイルを作り、それを読み出します。
こうしたデータファイルを作る時は、Perlでは文字列を分割するsplit関数を用いて読み出し、書き込む時はjoin関数を使うと便利です。その上で適切に読み込みオープン・書き込みオープンを使い分けながら、データファイルを読み書きしましょう。

定数をフラグとして扱う

また、C言語などでよくみられる方法として、「定数をフラグとして扱う」というのがあります。
フラグは、論理和論理積で、「FLAG_ONE | FLAG_TWO」とか、「FLAG_ONE & FLAG_TWO」などとし、if文やswitch文などで、こうしたフラグの「論理的な合一と複合を示す値」を取るのです。
この他、C言語の論理演算では、三項演算子「~ ? ~ : ~」などもよく使われます。
また、定数や構造体の型はヘッダファイルに記述し、それを使う全てのC言語ソースファイルでそのヘッダファイルをincludeします。場合によっては、小さな記述であればヘッダファイルに関数のコードの実体を記述することもあります。

関数と制御の中でデータを扱うことが基本

プログラミングの初心者向けのことを言うと、「関数と制御の中でデータを扱うことが基本」であると言えます。
関数とは、ライブラリ関数のことです。制御とは、if文やfor文のことです。データとは、変数やリテラルのことです。
if文やfor文の中で変数を扱いながら、システムに存在するAPI関数を呼び出すことができれば、それでプログラミングは簡単にできています。
それ以上は、ルーチンワークです。どのような設計でルーチンを実行するか、ということが基本になります。ですが、それはやっている中で変えていけばいいとか、必要に応じて書き直していけばいいのです。
基本として言えるのは、「データをどのように扱うか」ということです。データを扱うこと、データを渡すこと、データを参照すること、データを変更すること、それ自体がプログラミングなのだと僕は思います。

型は大切

また、プログラミングを行う上で、型は大切です。それは、データを扱う上で、「どのような種類のデータを扱うか」が決まってくるからです。
最近は動的型付け言語というものが流行っていて、動的にその場その場の変数の内容に応じて、型をダイナミックバインディングできる言語もあります。
ですが、僕は静的型付けの方が好きです。それは、「きちんと正しくコードが動くこと」を考えているからです。
動的か、静的かという永遠の論争をするよりも言えることは、動的型付けの言語であっても、「そのデータが文字列か数値か特定のクラスか」を考える、ということは、どんな言語でも変わらないということです。
データを扱う上で、そのデータがどんな種類の型であるかを、意識するようにしましょう。そこで、「データをどのように処理したらいいか」も同時に決まってくるでしょう。

プログラムの中で確保したものはプログラムの中で廃棄する

Javaのようなガーベッジコレクションを搭載した言語が増えている中で、時代遅れだと言われるかもしれませんが、C/C++のプログラミングをもし行うのであれば、「プログラムの中で確保したものはプログラムの中で廃棄する」ということを守りましょう。
これは、単にmalloc()とfree()だけには限りません。多くのC/C++フレームワーク、特にWindowsプログラミングなどを行う場合であっても、プログラムの中で確保したリソースは、プログラムの中で廃棄しなければなりません。GetしたものはReleaseしなければならないのです。
ローカル変数などは、スタックで管理されるため、スコープを終えれば自動で削除されますが、malloc()で確保した領域は、ヒープで管理されるため、「明示的に解放しなければメモリリークが起きてしまう」可能性があります。

プログラミングに必要な考え方

よって、プログラミングを行う上で必要となるのは、

  • 1.演算子
    • 計算や論理の一致・適合を行う。
      1. や==など
  • 2.変数の格納
    • データを確保・参照・変更する。
    • varやstructなど
  • 3.条件付き制御フロー
    • 条件に応じて処理を行う。
    • if文やfor文など
  • 4.関数呼び出し
    • システムに存在する関数を呼び出す。
    • printfやechoなど
  • 5.関数の定義
    • 呼び出すための関数を自分で作成する。
    • ルーチンの作成
  • 6.メモリの管理
    • 確保したリソースをきちんと廃棄する。
    • スタックとヒープ
  • 7.外部ファイルへの依存
    • データを永続化する。
    • 設定ファイル、データベースなど

などとなります。これらがきちんとできれば、あなたは一流プログラマです。

ポインタ

なんであれアドレスを必要とする場合は意外と多い

ポインタの使いどころとして、「なんであれ変数のアドレスを必要とする場合は意外と多い」というのが言えます。
たとえば、文字列や配列をアドレスからアクセスする場合に、その文字列や配列の「最初の位置」に、「アドレスというラベル」を保持することで、そのラベルから実体へアクセスします。
動的なメモリ確保についても同じで、確保した動的メモリ領域に「アドレスというラベル」からアクセスするのです。
言ってみれば、一種の「ファイル名」あるいは「インデックス」のようなものです。アドレスという「その場所を指し示す位置情報」があることで、どこからでもその位置情報にアクセスできるのです。
これは、たとえば、引数のポインタや参照型変数、あるいはオブジェクト指向の動的なインスタンスあるいはクラス内の動的メンバについても同様で、「位置情報を持っていることで、どこからでもダイレクトにアクセスすることができる」また「ダイレクトにアクセスする変数を自分で削除しない限り永続的に保持することができる」ということを意味します。
データ構造などでも、「位置情報を保管した変数からアクセスする」ということができます。たとえば連結リストの次のメンバをポインタで保持することで、「位置情報をメンバとして維持し続けることができる」のです。これは、単にポインタというだけではなく、「そのポインタを操作する関数処理までを考えた上でのデータ構造」であると言えます。ここから、ポインタは単なる位置情報ではなく、アルゴリズムによって処理されるデータ構造になり、話はオブジェクト指向カプセル化まで広がっていくのです。

システムレイヤー

GTKのレイヤー

プログラミングにおいては、よく「高水準」とか「低水準」といった言葉で、「レイヤー分け」という考え方が行われる。
たとえば、以下はGNOMEで使われているGTKのレイヤー。

ここでは、X11 - Xlib - Cairo/GLib - Pango/GDK/ATK/GIO - GTK - GNOME etc.というレイヤーがあることが分かる。

UNIXにおける水準

まず、高水準・低水準とは、多くの場合、「よりマシンに近いか」「よりユーザーのやりたいことや機能に近いか」といったことから使われる言葉である。
たとえば、Linuxカーネルは比較的低水準のレイヤーである。マシンのデバイスコントローラの情報はデバイスドライバが唯一知っていて、それをカーネルが使って操作する。
カーネルの移植性の低い低水準のコードは、機種依存のi-nodeを直接操作するストレージ操作や、TCP/UDPを用いたプロトコル(送受信の手順や決まり)やコネクション操作とルーティングやパケット送受信操作などがあり、これの少し上に、移植性の少し高いVFSを用いたファイルシステムや、socketを用いたネットワークの高水準な機能があり、それらを行うことで、「カーネルレベル」の操作を行う。
カーネル内部の処理よりも高水準なのは、システムコールである。カーネルシステムコールを受け付け、プログラマシステムコールを使ってカーネルに新しいサービスをお願いする。
少し上の水準では、Cライブラリの水準がある。コマンドやデーモンなどは、Cライブラリとシステムコールをバランスよく使いながら、移植性の少し高いコードを書く。
さらに上には、シェルによってコマンド操作をするユーザーフレンドリな環境があり、シェルスクリプトなどは単純なスクリプト処理を行う。

GUIにおける水準

GUI環境であれば、こうしたUNIX環境の上に、X11 - Xlib - GTK - GNOMEなどの高水準なシステムプログラムがある。
X11では、低レベルなウィンドウの表示操作や、マウスやキーボードやディスプレイの間でのビットマップ表示操作を行う。XはXプロトコルでXサーバーとXクライアントの間で通信を行う。Xlibを用いることで、Xプロトコルの詳細を知らなくても、簡単なライブラリAPIでXのプログラマブルな操作ができる。さらにメニューやボタンを実現し、コンテナやボックスの概念を導入し、強力なオブジェクト指向と使いやすいシグナルインターフェースを使うことのできるGTKがあり、GTKはGLibやGDKの上のレイヤーで成り立つ。GTKを使って作られたデスクトップ環境がGNOMEであり、この上にGNOMEアプリケーションが動く。
KDEであればX11 - Qt - KDE Frameworks - Plasmaとなる。
この上でユーザーはユーザーフレンドリなGUIアプリケーションを実行する。たとえばMozilla FirefoxLibreOfficeなどである。

サーバーにおける水準

サーバープログラムであれば、ApacheなどのWebサーバーや、JavaRubyなどのミドルウェアの上に、CGIRailsなどのAPサーバーがあり、MySQLPostgreSQLなどのDBサーバーがある。
このように、コンピュータでは「低水準から高水準へ」という考え方の下で、システムが成立している。自分がどのような水準のプログラムを書きたいかという目線から、どれくらいの水準でソフトウェアを開発するかを考える必要がある。

アプリケーション開発

バッファとストレージ処理

テキスト処理を行うのであれば、内部のテキストデータをバッファに保持する必要があります。
巨大なテキストデータやストレージを扱う上で、考える必要があるのは断片化と永続化の問題だと思います。
ストレージやファイルシステムなどで、データの途中にデータを保管したい時に、単純に全てひとつの記憶領域やブロックに保管を行うと、挿入や変更に時間がかかります。かといって複雑に別々の場所に保存すると、ストレージが断片化する恐れもあります。
また、バッファやインスタンスのデータをメモリだけに保持していると、プロセスが終了した時に消えてしまいます。こういう時は永続化(プロセスが終了してもデータが存続できるようにデータを保存すること)を行わなければいけません。
コツとして、データを読み書きしたり表示したりする際に、テキストデータであれば、バッファのサイズは4096などと決め打ちにして、少しずつバッファに読み込んで表示するようにすると、メモリの使用量を少なく抑えられます。

テキストエディタの開発

プログラムを開発するコツは、「プログラムに必要な機能をよく分析すること」です。
たとえば、テキストエディタを作るのであれば、バッファに文字列を格納し、テキストエリアに整形して表示する機能がまず必要です。バッファが更新されたら、ビューも更新しなければいけません。
また、ファイルから読み込む機能、ファイルに書き込む機能も必要です。
また、検索や置換、あるいは比較のような機能があると、テキストエディタらしくなるでしょう。テキストエリアには、キーワードを色分けする機能(シンタックスハイライト)があると良いでしょう。
機能を分類できたら、今度はどのようなクラス設計でそれを実現するかを考えます。まず、バッファをメンバ変数としたエディタークラスを作ります。同時に、シンタックスハイライトとビューの常時更新機能をつけたテキストエリアコンポーネントを作ります。同時に、ファイルを管理する開く・保存機能を作ります。最後に、検索と置換の関数を作ります。これらをまとめて、エディタークラスに実装します。
常時更新機能を実装するには、バッファを編集するのに専用のインターフェースを設けて、テキストエディタにビューを更新する関数を作り、バッファのインターフェースが呼び出されたら、必ずその更新関数が呼び出されるようにします。この更新関数はどこからでも呼び出せるようにして、ファイルを開いたり保存したり、設定を変えた時にも呼び出します。また、シンタックスハイライトを作るには、テキストエディタコンポーネントが表示する処理を行う時に、バッファ読み込みとビューの表示の間に介入して、ひとつひとつのキーワードを解析し、その情報をテキストにタグのような形で付け足して、表示する処理の部分で、テキストに付属された情報の通り、テキストエリアで文字色を変えてフォントを表示するようにします。
そのように、どんな機能が必要かを考えることで、クラスの設計もしやすくなります。

ワープロの開発

ワープロを作るために必要なのは、
・データの保管と読み書きをするデータオブジェクト
・文字や画像を表示する配置オブジェクト
・データオブジェクトと配置オブジェクトの変換をするメソッド
・配置オブジェクトを表示するメソッドとビュー
・ビューを操作した時に配置オブジェクトとビューを更新する描画モード
・配置オブジェクトの編集機能
ではないかと思う。
きっと、ブラウザなども同じ要領で作れる。MFCにはドキュメント・ビューという概念が存在するが、僕はそれには詳しくない。
基本的に、配置メソッドは四角形の領域を表示するようにして、表示メソッドによってビューに「全ての配置オブジェクトを表示する」機能をつけて、描画モードによって操作に応じて部分的に配置オブジェクトの表示を更新する機能をつける。そして、保存する時はデータオブジェクトに変換すれば良い。
オブジェクト指向は、クラスによってデータとメソッドを一体化させ、その上でメモリの管理をオブジェクト単位で行い、オブジェクトを簡単に作成・削除し、グローバル変数のようにクラス内部のメソッドからオブジェクトのメンバ関数を処理するものだ、と考えると良く分かる。

Webブラウザの開発

言語とライブラリの基本が分かったら、クラス図を書きましょう。
クラス図とは、クラスとクラスの関係を考える、モデリング(図)の一種です。
それぞれのクラスの属性(メンバとなる変数と関数)とクラス間の関係をここに書きます。
クラス図が書けるようになったら、あなたはもうれっきとしたプログラマの仲間入りです。
実際にプログラムを開発してみましょう。コンパイラでもブラウザでもなんでも構いません。きっと良いプログラムができると思います。
たとえば、ブラウザを作るのであれば、それぞれのキーワードに応じたクラスを作って、そのクラスのメソッドを使うようにインスタンスを作ることになるでしょう。この時、共通の親クラスやインターフェースを作ると、Javaらしいプログラムになるでしょう。
また、JavaScriptからDOMで操作することになるのであれば、簡単なコンパイラも作る必要があります。これも、HTMLと同じように、キーワードごとにクラスを作れば、きっと作れるはずです。
また、ブラウザの制御として、ブラウザのGUIクラスも作りましょう。このGUIクラスには、ウィンドウにHTMLファイルを読み込んだり、ナビゲートしたり、通信を行ったりする機能が必要となるでしょう。
あとは、HTMLとCSSJavaScriptを解析する「パーサー」が必要です。そこまで分かったら、もう、できたようなものです。あとは、それぞれのクラスで、グラフィックスをいかに描画するか、という処理を抽象的・汎用的に書くことになるでしょう。
唯一面倒くさい点は、OSによって異なる整形されたグラフィックスの表示の仕方です。そのために、ひとつバッファを描画するクラスを作りましょう。そして、このクラスを用いてグラフィックスを表示します。リアルタイムな表示にするのは難しいかもしれません。CSSの表示もこの中でCSS専用のクラスを作って使いましょう。これは「レンダリングエンジン」に相当します。
要するに、オブジェクトツリーを決められた通り表示するレンダリングエンジンを作る必要があります。このツリーをDOMと同じにすれば、JavaScriptからも操作しやすいでしょう。また、タグごとにクラスを作ると言いましたが、最低限のクラスだけを作って、あとはリソースファイルなどで対応することもできます。あるいは、線と文字と背景とレイアウトを表示するそれぞれのクラスを作った上で、点線や色のついた文字や線や背景などは派生クラスで対応しても良いでしょう。そのようにすれば、きっと簡単なブラウザを作ることができます。
タグのクラスとして必要なのは、全ての親になるGeneralTagと、SpanTagとDivTagが必要になります。ここから、PTagのようなものを作ります。そして、TagTreeクラスを作って、HtmlParserクラスがTagTreeを生成し、DomクラスがTagTreeをDOMから制御できるようにします。あとは、CssPerserクラスでCSSを解読し、ここにLayoutクラスを入れて線や文字・背景の色やレイアウトを行います。ViewerクラスでTagTreeオブジェクトをLayoutクラスとともに表示できるようにしたらビューは完成です。BrowserWindowクラスを作って、ブラウザからビューを操作できるようにしましょう。
ここで、それぞれのタグクラスが何をするのかが問題ですが、単純に、サイズや色や文字情報などを保管します。そして、CssParserで解析した「どんなオブジェクトは何色」という情報に基づいて、Layoutクラスが一気に表示するようにします。
良く考えると、オブジェクトを識別するためのオブジェクトIDが必要です。また、一気にメモリに確保するとメモリを大量に食うため、今作業しているそのそれだけに集中できるようなメモリアロケーション機能が必要になるでしょう。
みんな、Webブラウザのようなものは難しすぎて誰にも作れないのだろうと考えているかもしれないが、意外と簡単である。
まず、HTMLを装飾と文字データの属性を持ったレイアウト情報(レイアウト文字データ)に変換する。ここでCSSを考慮しても良いだろう。そして、与えられたオプションから四角形の領域を表示する部分を実装する。つまり、「divとspanだけを作れば作れる」からである。
pタグやh1タグのようなものは、全部divとspanを使って作れば良い。
レイアウト部分が作れたら、次は装飾部分を作る。まず、文字を表示しなければならない。次に、文字と背景と線に色をつけなければならない。
最初からCSSを考慮した設計にすると、あとで楽が出来るだろう。
また、その上で、画像を表示したり、さまざまな機能を作ったりする必要はある。JavaScriptの実装も難しいし、そのためにはDOMを実装しないといけない。
だが、これくらいの、HTMLをパースして領域を表示する部分は、むしろ、僕のロボット(人工知能)のプログラムを参考にすると上手く作れるだろう。HTMLを読み込んで、CSSを解釈し、タグをパースし、領域とレイアウトを決め、装飾をつけて、最終的にモニターに表示するのを、ひとつの制御の流れとして実装すれば、あとはオプションを解釈して動作を変えるだけで、おそらく作れるだろう。

実際のレンダリングエンジンの仕組み

実際のレンダリングエンジンでは、リソースをダウンロードした後で、HTML→DOM、CSS→CSSOMと呼ばれるオブジェクトモデルにそれぞれ独立してパースし、JavaScriptコンパイル・実行した上で、DOMとCSSOMをマッチングさせてレンダリングツリーを構築し、最後にレイアウト・ペイント・コンポジットを行う。

コンパイラの開発

以下は僕の主観的方法論を書いただけにすぎず、経験や知識に裏打ちされた正しい方法ではない。
まず、パースの段階で、字句解析と構文解析を行い、関数の呼び出し元と呼び出し先が適切かどうか、変数やキーワードなどの宣言と利用が適切であるかどうかを確認し、文法的な誤りがないかを確認する。
次に、文法的記述を解析して、言語的なパースツリーを作り、言語を中間言語・三番地コードに変換する。変数やサブルーチンの記述をポインタとジャンプ命令に変換し、条件分岐・繰り返しなどの文法的記述を変換する。
そして、中間言語に対して最適化をかける。
最後に、アセンブリ言語を出力し、アセンブルして機械語のオブジェクトを出力し、オブジェクト同士をリンクする。

インタープリタを作る

(注記:以下の内容は自分が考えて記述したため、一般的な方法とは異なるかもしれません。)
インタープリタを作るためには、まず字句解析器で言語のキーワードや変数や関数の識別子を拾って、構文パターンやシンボルに変換する。これにより、ifやforは中間言語表現となり(本当はもっと後のフェーズで行う)、$nameやfunc()は識別子のシンボルとなる。
次に、構文解析器によって構文パターンを解析し、パースツリー(最優先で評価すべき内容から順に評価していくためのツリー)に変換する。たとえば( (1 + 2) - 3)のようなコードやfuncA(funcB())のようなコードやx = y - 3のようなコードを解析してパースツリーにする。
最後に、状態ベースの仮想マシン(シンボル名などをステートフルに保持するインタープリタ仮想マシン)により、パースツリーをひとつひとつ評価し、中間コードあるいは機械語に変換して処理を行う。$nameなどはセグメントにおけるメモリアドレスに変換され、ifやforやfunc()などはジャンプ命令などに置き換えられる。
そして、最後に実行する。
基本的にこんな感じだが、状態ベースの仮想マシンにはスタックやヒープによる変数の保持や、型の評価なども行わなければならない。基本的にこれくらいを作ることになるが、「evalさえあれば何とかなる」というところも多い。

3番地コード

3番地コードとは、2つの入力と1つの出力のアドレスによって成り立つコード。
たとえば、

x = y + z

のようなコードである。
コンパイラを作る上で、中間形式のパターンの1つとして知られている。以下のようなコードは、

x = 3 + (1 + 2)

このようなコードに直される。

t1 = 1 + 2
x = 3 + t1

処理系によっては3番地コードはコンパイラの最適化をかけるのに適している。
3つのアドレスだけのコードだから、「3アドレスコード」と呼ばれる。これを日本語に訳して、「3番地コード」である。

カーナビの開発

たとえば、カーナビのシステムを作る場合。まずは、地図データがあります。この地図データを、まず、変数に格納します。
そして、機能を作る前に、マッピングとして、地図データの基本的な操作メソッドと、ディスプレイやモニター画面に地図を表示する関数群(API)を作ります。
そして、基本的な地図の機能、たとえば拡大・縮小、回転、移動、のような機能を作ります。これは画像的なライブラリを使うと良いでしょう。
地図を解析して、道順を知るための機能は、まず、膨大な地図データをデータベースに登録します。そのために、画像から自動で地図データの「属性」を取得し、自動で登録する解析プログラムを作ります。
このデータには、道路の長さと、必要な移動時間、そして道路の右端と左端の位置情報や、道の分岐の情報を登録します。
そして、現在地と目的地の位置情報から、「どんな道のりのパターンがあるか」を、道路の右端と左端の位置情報や分岐の情報を上手く繋ぎ合わせることで、全パターン洗い出します。
そして、それぞれのパターンにかかる時間を計算し、それをソートして完成です。
その上で、さまざまなナビゲーションに必要な機能(道のりを別の色で表示したり、状況に応じてナビゲーションする機能)をつけて、カーナビのシステムを作ることができます。
このような場合にも、必要なのは、「データを保持する部分と、そのデータを操作する関数の部分を作ること」です。
さらに言えば、「どの道からどの道に繋がるか」というリンク情報をデータベースに登録しておくと、あとあと便利かもしれません。また、さまざまなボタンやメニューを作って、イベント駆動のメソッドを書く必要があるでしょう。そして、きちんと動くかを確認するために、テスト関数のようなものを用意して、さまざまな条件と結果をチェックするようにしましょう。現在位置を取得するGPS機能や、現在位置の変化とともに画面を移動させていく「リアルタイム解析機能」も必要になるでしょう。

新しい分散ネットワークの開発

コンピュータが可能としたのは、「システム構築の簡便化」だけではない。彼らはインターネットという「世界中のつながった、誰でも参加できるオープンな仮想空間」を作った。インターネットは、コンピュータ技術を楽しみにする以上に、僕は将来においてとても重要なものになると思う。それは、「インターネットをいかに利用するか」はまだまだ未知数だからである。だが、僕はそうした「未来のインターネット」は、おそらく、そんなに良いものにはならないと思う。それは、タリバンやISのようなテロ組織がインターネットを「支配と戦争のために利用する」からである。彼らはインターネットを最後の戦場として、アメリカのインターネットとイスラムのインターネットが互いに争うようになる。だが、僕はこうした「戦争のインターネット」は一時的なもので、そのうち、「インターネット憲法」が定められると思う。だが、憲法が決まってしまえば、インターネットは自由が無くなり、つまらないものになるだろう。今のように、オープンに参加し、何をしても処罰されないインターネットではなくなる。義務と法律がインターネットに生まれた時点で、インターネットの価値は無くなり、ただのコモディティ的なものへと劣化することだろう。ただ、それでも、インターネットの「世界中を繋げる可能性」は未知数で、無くなるわけではない。だから、たとえば、現実世界とは本当に全く違ったコミュニティができる可能性もあれば、現実世界の中で何かをするためにインターネットをもっと利用するようになる。こうした発想は、今、まさにどんどん生まれている。だが、今までの「Webページ」を使ったインターネットには限界があるかもしれない。もう一度、誰かが「本当の分散ネットワーク」を作る可能性はある。だが、単純にWebページを見るだけ、というスタイルそのものが変わってしまうことは避けたい。インターネットの良さは、ページをブラウザが表示するという、「誰にでも分かる単純な社会の仕組み」に存在する。これを複雑なアプリケーションにしても、それは流行ることもなく、インターネットそのものの分かりやすさや自由度を劣化させるだろう。
僕が思うに、SNSのようなものはそのうち流行しなくなる。逆に、2ちゃんねるのようなシンプルな仕組みを持った掲示板サービスに対して、専用ブラウザのような「高度なことも必要に応じてできる」ようなソフトウェア技術は発達する。IRCで良いじゃないかという意見はあるかもしれない。だが、僕は「シンプルなSNS専用ブラウザ」という発想が良いと思う。SNSは高度かつ複雑になりすぎている。シンプルに使える、一目で分かる新しいSNSに対して、たくさんの機能を提供する専用クライアントがあれば、僕はそれが正しいと思う。そして、サーバー側は、アカウントとデータの管理しか行わない。ビューは単純なものを表示し、データベースの中のデータはどこからでも、どんなクライアントからでもアクセスできる共通のものを更新・管理する。そして、クライアント(専用ブラウザ)の側から強力な機能を提供する。たとえば、全てのSNSを見て、その中でどんな書き込みがあっても最新の情報をスマホに通知するような、そういう仕組みをクライアントとして提供する。まさに、これが昔の2ちゃんねる専用ブラウザである。サーバー側は可能な限り単純化し、データの保持と提供しか行わない。クライアント側は可能な限り自由にし、何でもクライアント側のアプリケーションでできるようにする。サーバー側のシステムも、クライアント側のアプリケーションも、全てオープンソースにする。オープンソースにしない商用の業者がアプリケーションを作っても良いが、オープンソースのものも必ず用意する。
また、サーバー側のブレイクスルーとして、たとえばP2Pのように分散ネットワークにすることも考えられる。クライアントを専用アプリケーションにするのであれば、今のWorld Wide Webの仕組みを継承する必要はない。誰もが簡単にページ(ホームページと同じ)やグループ(掲示板と同じ)や、ニュース、ブログ、つぶやき、拡散・シェア・通知の機能などを、この「シンプルSNSサーバ」に実装し、クライアントがそれぞれの独自の「操作スタイル」から操作することができるようにする。つまり、データベースには、その投稿の内容と、その投稿がどんな意味を持っているかという情報を管理し、常に更新されるようにするための「P2Pサーバ」(そもそもP2Pはサーバー・クライアントシステムではないため、この名称は適切ではない)となり、クライアントは、P2Pサーバの適切なデータを操作するものとなる。それぞれのノードが常に情報を発信し、全てのプラットフォーム(Windows, Linux, Mac, スマホなど)に対してオープンに公開され、どんな風にその情報を整形して操作しても良い。インターネットと違う一番大きな点は、サーバーを構築する必要がない、ということ。レンタルサーバーを使って、有料でサーバーの費用を負担する必要がない。それぞれのノードは「共同体自治区」を形成する。自分の共同体自治区に含まれている人々の情報は、自分が共同でホストする。サーバーをレンタルせずとも、情報をP2Pで発信できる。動画サイトも漫画サイトもフリーソフトのダウンロードも可能にする。ただし、Winnyを目指しているわけではなく、匿名通信や第三者の仲介を基本にはしない。
ただ、本当のところを言うと、このネットワークでは自分たちの共同体自治区を共同でホストするだけを今までのWebサイトと同等に行うため、クライアントプログラムの実装を少し工夫すれば、匿名ネットワークや第三者が介入するアップロードやダウンロードの仕組みは実現できる。だが、これは全く逆のこともできることを意味する。すなわち、犯罪者のWebサイトや犯罪ファイルのようなものは、自分たちの共同体自治区から締め出してしまえば良い。たとえば、子供たちが見るページの共同体自治区は、その子供たちが使うアプリケーションが共同でホストするため、「自分たちの意に合わないサイトは全て消す」といったことができる。だが、これはある意味危険である。中国人が政府の批判を書くために、匿名ネットワーク機能をONにした上で、少しでも政府寄りのメンバーを全て排除することができる。おそらく、Winnyの開発者はそういうネットワークを開発したかったのだろう。

役所自動化システムの開発

僕は、最後に、この世界を僕を王とする王国に変える。
実際のところ、民主主義や社会主義の指導者には何もできない。支持層の意見を聞く必要があり、自分の好きな政策は何もできない。
自分の政策を行いたいのであれば、独裁者になる必要がある。
そして、世界全てを変えたいのであれば、EUの大統領であることがもっとも適切である。
僕は、ドイツの保守右翼と社会主義者キリスト教徒とユダヤ人の支持を取り付け、ドイツの首相となり、そのまま、EUの大統領となる。
必要なのは、僕個人の権力を頂点とする、ひとりで決められる権力である。
僕は、自らコンピュータシステムを設計し、運用することで、ひとりで全てのことを決める。この世界の全てのことを、自分独りで決める。
また、コンピュータ・ネットワークが普通となった現代社会で、国を統一し各国のそれぞれの首脳が支配し外交する政治モデルは必要ない。
僕は、コンピュータを使った自動管理によって、分国行政を実現する。それぞれの国民の意見を聞いた上で、それぞれの国民に対して適切な行政サービスを、コンピュータが自動で管理し、どのような変化に対してもリアルタイムでその変化に対応する。そのため、きめ細かいサービスを行うこと、それぞれの国民に対して「本当に必要な支援」を適切に行うことができる。
また、法律からどのようにすれば適法かを判断する「法律AI」を作り、この法律AIが全ての会社に対して適切な契約と給与の支払いを行う。全ての人間の個人情報と労働状況をこのシステムはリアルタイムで監視し、全ての会社・全ての労働者に適切な給与の支払いを命じる。自由でも平等でもなく、必要な給与を必要な額だけ与える。
また、国家の政策は全てコンピュータシステムの設計の時点で決まっており、適切な場合に適切な政策を実行する。どんな時代の変化にも対応するために、万全のコンピュータシステムを設計・実装する。
僕は、このシステムをRed Hatとともに作る。僕がRed Hatチーフマネージャーになる。
また、EUの大統領となった僕は、ロシアと友好する。そのため、「EU・ロシアの巨大な文明圏」を僕は作り上げる。そのうちそこに中国やインド・中東やアフリカも加わり、僕は世界政府の皇帝となる。
システムの最初のバージョンは、それくらいのシステムを作って役所を自動化する。難しく見えて簡単である。法律と現実の人々の置かれた状況を照らし合わせながら、適切に「与えるべき金」を計算すれば良い。また、システムの以後のバージョンでは、格差を徐々に再分配によって平等に近づけていく機能や、失業者がでないよう全員に適切に雇用を与える機能を作る。これも、ただ条件と状況が増えただけであり、すぐに実現できる。ソフトウェアの設計自体は簡単で、3か月から6か月ぐらいの時間で実現できる。だが、データを集めることが難しく、制度や仕組みを運用するために必要なことが多いため、どこかにあるデータを使うのであっても10年はかかるだろう。制度や実際の社会に導入するのは50年単位の時間がかかる。

GUI開発

Linux/X11

Linuxでは、Linuxカーネルと少数のCUIプログラムによるベースシステムには、グラフィックスを表示する機構は存在せず、キャラクタベースの入出力による、コマンドライン操作のインターフェースしか用意されていない。
こうしたCUIのインターフェースでは、コマンド入力を読み取って、標準入出力やファイルシステムに対して、コマンドプログラムを実行して操作することしかできない。
だが、今のパソコンの全盛時代、こうしたCUIの操作端末だけを使う人は少ない。GUIのアプリケーションをマウスやキーボードを使って操作し、ビットマップをモニターに表示しながら、アイコンやメニューをダブルクリックして、ボタンクリックやダイレクトなテキスト入力によってアプリケーションを操作したい。
Linuxでは、こうしたグラフィックス操作を実現するために、X11あるいはwaylandと呼ばれるソフトウェアを使う。X11とはウィンドウシステムと呼ばれるソフトウェアで、UNIXでは伝統的にX11を使うことで、マウスやキーボードを使ってポインタを上下左右に動かし、グラフィックスをモニターに表示する「Xサーバー」と、そのXサーバーでユーザーが行ったイベントをメッセージとしてクライアントに伝える「Xクライアント」すなわち「GUIアプリケーション」の操作環境を実現する。
XサーバーとXクライアントはネットワーク上で接続されており、Xプロトコルと呼ばれる通信規格で通信を行うが、Xプロトコルの詳細を知らなくてもXクライアントがXサーバーとやり取りできるように、Xlibと呼ばれるライブラリが用意されている。
Xlibだけを使っても低レベルなグラフィックス処理はできるのだが、Xlibにはひとつ問題がある。Xlibには、WindowsMacでのGUIアプリエーションに用意されているような、ボタン、メニュー、リストビュー、ツリービューなどの「便利なウィジェット」が用意されていない。Xlibによるインターフェースは下層レイヤーでは必ず必要だが、Xlibよりも上位のレイヤーとして、Motif、GTKあるいはQtといった「ウィジェットツールキット」と呼ばれるライブラリがXには多くの場合存在する。こうしたツールキットを使うことで、フォームにボタンやメニューあるいはテキストボックスやラベルを簡単に張り付けたり、ボタンがクリックされたりメニューがクリックされた場合に応じて実行されるコードを別々の場所に記述する「イベント駆動のプログラミング」を行うことができる。
また、GTKを使う場合は、Gladeというアプリケーションを使うことで、フォームデザイナーで画面を見ながらウィジェットを配置し、その結果をXMLで吐き出してlibgladeライブラリを用いて読み込むことができる。また、GTKにはたくさんの言語バインディングがあり、標準のC以外にC++PythonRubyやmonoなどさまざまな言語で開発ができる。Qtでは、QtDesignerやPyQt/QtRubyなどが同様に存在する。
デスクトップ環境のGNOMEではGTKKDEではQtが使われている。そのため、GNOME向けのアプリケーションを書くのであればGTKKDE向けのアプリケーションを書くのであればQtを利用することで、システムと見栄えや操作感(ルック&フィール)を統一させたアプリケーションを作ることができる。GTKアプリケーションはGNOMEと調和し、QtアプリケーションはKDEと調和する。GTKやQtにはテーマエンジンも搭載されており、テーマを変更することで全てのアプリケーションの見た目を一括で変えられる。(アプリケーションのデザイン自由度が下がるというデメリットもある。また、テーマエンジンを介する分、表示も重くなる。)
また、ツールキットだけではなく、デスクトップアプリケーションを書くのであれば、設定・コンフィグのためのデータベースや、仮想ファイルシステムなどのインターフェースも必要となる。GNOMEでは、こうしたGTK以外の必要なコンポーネントライブラリも開発・提供しており、GNOMEアプリケーションを書くのであればそうした仕様に則ることが望ましい。また、KDEでもKDEフレームワークと呼ばれるフレームワークを開発しており、さまざまなデスクトップアプリケーションのためのAPIを提供している。これにはHTMLレンダリングエンジン(KHTML)のようなとても高度なものも含まれる。

Windows

これに対して、Windowsではカーネルにグラフィック・ウィンドウ表示機構が統合されている。低レベルなWindows APIを使うことでも、メッセージループによるウィンドウメッセージを中心としたGUIアプリケーションの開発ができる。また、MFC、ATL/COM、GDI、DirectXのようなC/C++向けのフレームワークを使うことで、Windowsネイティブなアプリケーションを開発できる。
また、Windowsでは近年.NET Frameworkと呼ばれるJava VMと良く似た機構が搭載されており、.NET Framework向けの言語であるC#Visual Basicを用いて、グラフィカルな「フォームデザイナー」を用いた開発が可能である。

COMとCORBA

Windowsでは、COMと呼ばれる分散コンポーネント技術が存在し、これを使うことで、アプリケーションの中に別のアプリケーションのビューやコンポーネントを埋め込んで再利用したり、分散コンポーネントとしてそれぞれのアプリケーションを配置し、ネットワークを通じてインターフェースから操作することができる。
これはとても先進的な仕組みだったため、GNOMEはこのCOMに影響されて開発が始まった。GNOME 2ではCORBA、GNOME 3ではD-Busを用いたネットワーク・オブジェクト・モデルを採用しており、Bonoboを用いることでアプリケーションの中にさまざまなコンポーネントを搭載することができる。そのため、表計算機能もPDF表示機能も簡単にGUIアプリケーションの中に組み込むことができる。KDEではKPartsと呼ばれる同様の機構がある。

その他のGUIプラットフォーム

その他のGUIプラットフォームとしては、JavaのSwingやMozillaXULなどがある。

GUIアプリケーションの開発

GUIアプリケーションは、現代的なOSの場合、低水準な「メッセージループ」と、GUIフレームワークを用いた「イベント駆動」や「コンポーネントの継承」によって行います。
IDE統合開発環境)によるGUIフレームワークでの開発は、以下のようになります。

こうしたGUIアプリケーションで必要となるのが、自分の使うプラットフォームで使用されるGUIフレームワークの仕様の知識です。特に、OSや言語・ライブラリだけではなく、MFC, Windows.Forms, GTK, QtなどのGUIフレームワークについての知識に習熟する必要があります。
また、こうしたGUIアプリケーションを作る際に、巨大な会社のプロジェクトであれば、「自分でコンポーネントフレームワークを作る」といった方法がとられることもあります。Adobeのような巨大企業なら、そうする必要があるでしょう。そのためには、Windows APIやXlibなどの低水準のAPIを用います。

GUIアプリケーションの設計と実装手順

色んなやり方や色んなプログラムがあるため、一概に「このように開発しろ」とは言わないが、アプリケーションの設計と実装の手順の一例として、以下が参考になるかもしれない。
まず、どのような処理が必要になるか、明確化する。
・データ(あるいはデータ属性)をどのように保管し、参照し、読み書きするのか?ビューの表示機能にどのようにデータを与えるのか?そのためにどのように変換・保持するのか?
・ビューをどのように表示し、レイアウトや再描画をどのようにするのか?ユーザーは表示されたアートワークをどのように(マウスやボタンによって)操作するのか?
・ユーザーが操作するインターフェース(UI)は、どのようなものにし、どのように表示・参照・変更・適用するのか?どのようなフォームやパネルやダイアログを表示するのか?
・プログラム自体の設定は、どのように保持・参照・変更・適用するのか?プログラムの処理の中でどのように設定を適用するのか?
・プログラムの主要な機能は何か?
・プログラムの主要な機能をどのように実現し、実装するのか?
・機能の呼び出しインターフェース(API)は、どのような規約(ルール)に基づいて構築するのか?
APIに基づいて、機能をどのように分割・相互参照・モジュール化するのか?
・プログラムの開発のベースとして、どのような技術を採用するのか?(コンソール、Windows、Web、フレームワークなど)
・どのようなプログラムにしたいのか?(多機能、軽量、簡単、プロ仕様など)
また、こうして出てきた「漠然とした全体像」を、明確に、それ以上細分化できないところまで細分化し、決まっていないことが何もないぐらい明確化する。
そして、明確化した内容を、実際のプログラムにするために、「クラス」と呼ばれる単位に分割し、クラスとクラスの関係性を記述する「クラス図」と処理の流れを記述する「シーケンス図」を描く。
最後に、これらに基づいてコードを書く。ここで、初めて、プログラミング言語の知識の内容を活かすことができる。
後日注記:実際のところ、上記はMFCのドキュメント・ビューのような場合に限られる。もっとより一般的には、「処理の流れをどうするか」「内部的な設定情報をどのように保持するか」「ライブラリや再利用可能なコンポーネントをどのように利用・構築するか」などといった具合になる。

GUI開発はコントロールの操作ができればできる

GUI開発というと、コマンドラインよりも難しくて、高度で複雑なフレームワークの知識が必要であるかのように思うかもしれません。
ですが、実際のところ、DelphiC#のようなGUIに適したプログラミング言語を選んでしまえば、ほとんど「コントロールの操作」ができれば、作れてしまいます。
たとえば、テキストエディタに検索・置換機能をつけるなら、エディタコントロールの入力テキストをバッファを格納する文字列型の変数にコピーし、そのバッファ文字列に検索・置換をかけて、元のコントロールに戻すだけで作ることができます。
他にも、Shift+Spaceを押したら、さまざまな顔文字やアスキーアートの一覧を出すように、小さなリストビューウィンドウを表示して、そこからEnterを押せば顔文字を挿入できる、といった「2ちゃんねるに必須の機能」は、DelphiC#なら簡単に作れます。
ネットワークからHTMLデータをダウンロードし、正規表現で整形して表示する、などといったことも、IEコンポーネントなどを使えば、そんなに難しくはありません。独自のテキストビューに表示したいなら、独自コンポーネントを作る必要があり、少し難易度は上がりますが、そこまで困難ではありません。HTMLを整形してツリービューにひとつひとつのアイテムを格納するためには、ある一定の「テンプレート」や「記述規則」があれば、DelphiC#で簡単に作れます。
ここまで言って気付かれた方も居るかもしれませんが、これらは全て2ちゃんねる専用ブラウザの機能です。僕は昔そうした専用ブラウザを研究・開発していたことがあります。理由は2ちゃんねるが好きだったからです。ですが、その時はDelphiC#などの知識がなく、バグだらけになってしまいました。それでも、単純なHTML整形機能やメモ帳からのShift+Enterによる投稿機能などはそんなに困難でなく作れました。

Windowsプログラミングの問題

僕が思うに、Windowsプログラミングの問題とは、「自分で何も作っていなくて、結局OSを作らなければ意味がない」ということです。
C#VBなどで、コントロールを操作するプログラムを開発することは簡単です。APIさえ分かってしまえば、プロパティとイベントとメソッドを最低限書くだけで、どんなフォームやダイアログでも表示できますし、その中のさまざまな要素を変更したり、追加したりすることはとても簡単です。
仕事でプログラムを開発するのであれば、この「簡単にウィンドウプログラミングができる」という利点は優れています。特に.NETでは豊富で使いやすい整理されたクラスライブラリがあるため、イベント駆動とライブラリだけで、簡単に何でもできます。
ですが、ここにある問題はひとつです。「自分で何も作っていないから、何もしていないだけ」ということです。
確かに、既にあるクラスを継承した独自のコンポーネントクラスを作ったり、デバイスコンテキストを操作してグラフィックスをGDIなどで描くためには、たくさんのコードが必要であり、必ずしも自分では何もしない、というわけではありませんが、C++の機能とWindowsAPIをいくらか使うだけで、「自分では何もしていなくて、中身の仕組みも一つも分からず、何一つ面白くない」ということになってしまうのです。
これは、僕が今でもオープンソースUNIX系のOSが愛される理由ではないかと思います。プログラミングを行う上で、APIを「使う側」だけではなく、「使われる側」のコードもプログラマは読みたいのです。
そういうわけで、X11GTKやQtのコードを見たい、という方は多く居ますが、あまりきちんと理解できたという人は見受けられません。それは「そもそもUNIXGUIなんかありえない」からです。UNIXコマンドラインで使うのが基本であり、GUIのことは誰も触れず、教えず、使うことはあっても、GTKアプリを開発する機会がほとんどなく、GTKのコードを見たいという人も少ないのです。
最近は.NET Coreという「.NETのコア部分をオープンソース化する試み」もマイクロソフトによって行われていますが、どちらかというと僕はそちらに期待します。マイクロソフトオープンソースをやるのであれば、僕はマイクロソフトを全力で応援したいです。

オブジェクト指向の基本

オブジェクト指向

オブジェクト指向について。
オブジェクト指向は、大規模な開発を行う時に用いられるプログラミングの考え方である。
クラスベースのオブジェクト指向言語では、クラス(オブジェクトの設計図)の中にメンバ変数とメンバ関数(メソッド)、そしてアクセス指定記述を書く。
これは、オブジェクト(対象)に対してメソッド(方法)を記述する、と言う、抽象化と記述の方法であり、作法である。
たとえば、C言語のprintfをオブジェクト指向言語C++で実装するなら、文字を表示するための個々が個別に持つ文字列をメンバ変数(対象)とし、表示するため抽象的な方法を処理としてメンバ関数(方法)に書くことが出来る。そして、

CStringFormat str = new CStringFormat();
str.set("Hello, I am Linda.\n");
str.print();

とすれば、オブジェクト指向的だ。
関数の引数の型をオブジェクトと同じように設定することで、クラスと同じことは出来る。だが、それだと、派生クラスを作ることが難しい。オブジェクト指向なら、継承をすることで、一部の処理だけを書き換えた新しいメソッドやプロパティを持つ派生クラスを作ることが出来る。
C言語オブジェクト指向言語ではないが、GNOMEではGLibと言うC言語オブジェクト指向を実現するライブラリを開発することで、Cでオブジェクト指向を行っている。その上で、色んなプログラミング言語に対応するCORBAを使い、各言語のフロントエンドを作ることで、C++C#Pythonなど、たくさんのオブジェクト指向言語による記述に対応している。
さらにオブジェクト指向を発展させると、「コンポーネント」と言う利用方法が生まれる。これは、オブジェクト(コンポーネント)の内部に全ての外部からの処理に対するメソッドとプロパティを実装することで、コンポーネントの外部と内部を分け、外部からの操作と内部の対応処理による「操作」によってプログラムを記述する。そうすることで、コンポーネントを再利用可能にし、大規模な開発(たとえば巨大なGUIアプリケーションの開発)に対応している。
また、アクセス指定記述によって、クラスの内外からの操作(オブジェクトの呼び出し元や派生クラスのメンバ関数)による不用意なメンバ変数の書き換えを防いでいる。メンバ関数にプロパティ(setやget関数)を設定することで、メンバ関数の取得・変更処理もスマートに出来る。これを、「カプセル化」と呼ぶ。
これらのような技術は、GUIによる開発を行う上で、考え方として使われる。特に、ツールキットライブラリやコンポーネント、ドキュメント・ビュー・アーキテクチャなどをGUIで行う場合、メニューやボタンなどをGUIに表示したり、プログラムの内外から操作したりする時に、「安全かつ柔軟に操作」することが出来る。
オブジェクト指向言語は、C++Objective-CJavaC#VB.NETPythonRubySmalltalkなどがある。

オブジェクト指向は、データの作成・破棄と共有の仕組み

最近は、多くのプログラミング言語で、オブジェクト指向の仕組みを提供している。この、「オブジェクト指向が分からない」という人間が多い。
簡単に言ってしまえば、オブジェクト指向とは、データの共有と作成・破棄・取得・変更の仕組みである。
1.クラスは、メンバ変数とメソッドを持つ。クラス内のメソッドの中で、メンバ変数は共有される。
2.クラスは、インスタンスとなることで、作成・破棄される。また、一度インスタンスになったクラスのメンバ変数は、アクセサやプロパティを通じて、取得・変更される。
3.クラスは、一度作られた既存のクラスを継承し、メソッドを追加したり、枠組み(インターフェース)を実装することができる。
4.クラスは、実装の詳細を知らなくても、外部向けに公開されているインターフェースを使って、カプセル化して安全に取り扱うことができる。
つまり、オブジェクト(もの)として取り扱うことで、考えるべきことを事前に考えておき、メソッドの間で簡単にデータを共有し、使用する時にそれらのデータを簡単に作成し、破棄することができるような、そういう枠組みを作ってプログラミングを行うのが、オブジェクト指向である。

アロー演算子インスタンスハンドル

C++における動的なインスタンスにおけるメソッドの呼び出しや、PHPでは、アロー演算子(->)が良く出てきます。
僕は、このアロー演算子をどのように感覚で捉えて良いのか、良く分からず、アロー演算子が苦手でした。全てのオブジェクト指向言語は、アロー演算子ではなく、.(ドット)を用いてメソッドの実行を記述するようにしてほしかったです。
ですが、僕はこのアロー演算子の意味が、最近ようやく分かりました。それは、このアロー演算子における変数は、「クラスのインスタンスである」ということを認識したからです。
アロー演算子を、ポインタから関数が実行される、と認識している間は、分かっていません。これはインスタンスである変数から関数へと「変数の中身を送り出している」と考えれば分かるのです。
たとえば、

CString *pcStr = new CString;
*pcStr = "Test";
int n = pcStr->Find("T");

などと書いた時、pcStrという「インスタンス変数」を、Findという「メソッド」に送り出している、そういう感覚でこの記述をつかめば、アロー演算子を直観的に捉えられます。
インスタンスハンドルは、C++のようなオブジェクト指向言語だけではなく、CによるWindows APIなどでも出てきます。オブジェクト指向の本質は、インスタンスハンドルにあるのです。

オブジェクト指向はレシーバ・メソッド・メッセージ

C++Javaなどのオブジェクト指向を、「構造体の中の関数を呼び出す」と理解している人が多いと思います。
ですが、そのように考えると、いまいち、なぜオブジェクトのメソッドを呼び出して、オブジェクトそのものを操作するのか、ということが、分かりづらいと思います。
実際のところ、Smalltalkを参考にしたクラスベースのオブジェクト指向言語では、オブジェクト指向は、「レシーバ」「メソッド」「メッセージ」の関係だと表現できます。
レシーバとは、メッセージを受ける「受け手」のオブジェクトのこと。
メソッドとは、レシーバ・オブジェクトに働きかけるメッセージのことで、C言語などの構造化プログラミング言語では「関数」と呼ばれるものです。
そして、レシーバのメソッドを実行することを、「レシーバにメッセージを与える」と表現します。
そして、そうしたオブジェクトはクラスから作成します。クラスは、データ型の構造と関連するメソッドをまとめたものであり、基本のクラスから派生のクラスがひとつの「継承」関係の「階層構造」になります。
クラスには、あらかじめ決められたメソッドでしか操作することはできません。これを「カプセル化」や「隠蔽」と呼びます。
自分でデータ型を作る時は、既存のクラスを自分で継承します。自分でデータ型を追加したり、メソッドを追加したり、上書きすなわち「オーバーライド」することができます。
そう、オブジェクト指向とは、そうした「プログラムのリソースや方法を全てモノとして扱う」ということです。オブジェクト指向は、直訳すれば「もの指向」です。

getとset(プロパティ)

プログラミングの考え方として、「get」と「set」があります。
getとは、データを得ること。setとは、データを書き換えること。
プログラミングの基本とは、このgetとsetだと考えられます。特に、データを表示したり書き換えたり(破壊)するプログラムでは、これは重要な考え方です。
C#などでは、getキーワードとsetキーワードを使うことで、プロパティを作ることができる。これにより、Javaのようにstr.getValue()やstr.setValue("text")としなくても、「x = str.Value」や「str.Value = "text"」のように、取得と変更を=のような記号を用いて直感的に記述できる。

.の連鎖は面白い

オブジェクト指向の面白い点は、「.」の連鎖で「メソッドを実行して返るオブジェクトのメソッドを実行する」ということができる、ということです。
この.の連鎖は面白く、また分かりやすいです。VBDelphiなどのコードエディタでも、この.の連鎖を辿っていくことで、とても優雅にプログラミングを行えます。

大規模なプロジェクトではインターフェースが重要になる

大規模なソフトウェア開発プロジェクトでは、「インターフェース」の考え方が重要になります。
これは、オブジェクト指向言語だけではありません。たとえば、Linuxカーネルでは、デバイスドライバカーネルモジュールなどのインターフェースが重要になりますし、仮想ファイルシステムという機構では、たくさんのファイルシステムをひとつのVFSというインターフェースで操作します。また、カーネルの内部だけではなく、外部のプログラムとのかかわり合いとして、システムコールなどのインターフェースも重要です。仮想CPUや仮想メモリ機構を使う上でも、プロセスやバイナリファイル、メモリアロケーションインターフェースなどの規則や規範が必要になります。
UNIXには、POSIXという標準規格があり、多くのUnix互換OSではPOSIXの仕様を満たしています。ここではUNIXの標準的な規格が定められており、ファイルシステムのopen, close, read, writeなどのシステムコールも例外ではありません。カーネルだけではなく、libcのAPIもインターフェースの一種であると考えられるでしょう。

オブジェクト指向はもの指向

オブジェクト指向を考えるためには、英語で「オブジェクト」(object)と考えることです。
良く分からない方は、英語でobjectと考えれば良いのです。オブジェクト指向はもの指向です。なんでもものだと考えることで、オブジェクト指向の意味が分かるでしょう。

データ構造をインターフェースとともにカプセル化・隠蔽する

オブジェクト指向では、データ構造をインターフェースとともにカプセル化された「オブジェクト」と考えます。この「オブジェクト」としてプログラムを作り出す、という発想がオブジェクト指向です。
データ構造をインターフェースとともに隠蔽するように設計し、その場その場で作成する、ということは、大規模なプロジェクトにおけるプログラミングの簡素化をもたらすと同時に、クラスライブラリを使う側にとっても単純かつ使いやすくなります。これはC言語(特にK&R)などでも推奨されるプログラミングの方法です。インターフェースを適切に用意し、データ構造を隠蔽することで、プログラマは安全にデータを取り扱うことができるのです。

クラスからオブジェクトを作り、メソッドでアクセスする

オブジェクト指向を感覚でつかむためには、「クラスからオブジェクトを作り、メソッドでアクセスする」ということを掴むことです。
クラスとは、オブジェクトの設計図であると同時に、メソッドを使ってアクセスできるデータ構造です。データ構造の内部の仕様は隠蔽され、アクセスすることを許されたメソッドからしかアクセスできません。
また、コンストラクタとデストラクタによって、初期化と後始末のためのコードを書くことができ、単純な操作でもアクセサやプロパティを介することで、柔軟に必要になった段階で必要な部分に処理を書くことができます。
機能の拡張が必要になった段階で、既存のコードを変更せずにコードを継承・拡張することができ、インターフェースを実装することで共通の操作の記述から別の種類のクラスを操作できます。
クラスからオブジェクトを作り、メソッドを用いてアクセスする。この時、メソッドはレシーバに対するメッセージであり、同時にメソッドは独自に定義される演算子のようなものです。+や-の代わりに、obj.add(item)やobj.remove(item)とするのです。
オブジェクト指向とは、そうした「なんでもかんでもオブジェクト」にする、最近のプログラミングパラダイムです。

グローバル変数vsオブジェクト

実際のところ、Perlのように何でもグローバル変数でやっていると、大規模なプログラム開発を行う時に、何千行と書いているととても無理がでてきます。
大規模なプログラム開発では、データ構造とアルゴリズムを、関連した単位でパッケージ化し、そのデータ構造をひとつひとつオブジェクトとして作りながら、そのアルゴリズムをメソッドとして実行するようにします。
最初は分かりづらいと思いますが、「グローバル変数vsオブジェクト」のように考えると良いでしょう。

UMLをそのまま表現できる

また、オブジェクト指向のメリットとして、UMLで設計したダイアグラムをそのままプログラムの中で表現することができる。

データ構造をメソッドから操作する

要するに、オブジェクト指向とは、特定のデータ構造をメソッドから操作する、ということです。
これによって、自分でシステムにはない型や操作方法を作ったり、アクセスをそうした安全な方法でしかできないようにする、ということです。
加えて言えば、システムに用意されている型を改良することも、扱う時に共通の方法で同じように扱うこともできるようにする、ということです。
こうした「データを手で持って操作する」といった感じが、オブジェクトすなわち「もの」のように見える、というのが、「オブジェクト指向」という名前の由来なのです。

アクセスと再利用

僕は、プログラミングのコツは「アクセス」と「再利用」だと思います。
既存のコードやデータをどのように再利用し、コードやデータにどのようにアクセスできるようにするか、これを考えることで、プログラミングは成り立ちます。
プログラミングを行う上で、アクセスと再利用を上手く設計・実装することができれば、プログラミング入門者から中級者になれていると僕は思います。

クラスとインスタンスという機能群の構築

オブジェクト指向とは、要するに「クラスとインスタンスを使って、特定のプログラムの機能群を作り上げる」ということです。
たとえば、MVCのWebフレームワークであれば、ルーティング、コントローラ、ビュー、モデル、そしてアプリケーションのさまざまな基本機能(セッション管理やフロントコントローラ、データベースマネージャなど)をフレームワークとして実装し、これらのクラスを継承するなどしてアプリケーションを作ります。
こうした時に、クラスを上手く設計し、たとえば抽象メソッドを定義するなどして、「拡張可能な使いやすさ」を実現しながら、インスタンスをクラスの中に包括したり、継承や例外などを上手く使うことで、「再利用可能な巨大アプリケーション」を開発する、これがオブジェクト指向です。

データの保護

オブジェクト指向は、「データの保護」から生まれた考え方であると言えます。
たとえば、オブジェクトのメンバ変数xがあったとして、このxには0よりも大きな数しか入らないようにしたいとします。
この時、xを外部に単に制限なく公開してしまうと、このデータを保護することができません。これを、メソッドやアクセサ関数のみからアクセスできるようにし、そこでさまざまな対応処理を行うこと(xが0以下であれば0を代入するなど)で、「インターフェースというラッパーを一枚かぶせる」ことで、このデータを保護できるのです。

ジェネリック

テンプレートとジェネリック
C++では、STLの可変長リストのように、「どんな型でも使用できる汎用型」を提供している。これを、テンプレートと呼び、テンプレートを使ったプログラミングのことをジェネリックジェネリクス)と呼ぶ。
たとえば、文字列型をリストに使ったり、数値型をリストに使ったりする時に、その型名をクラス名と同時に宣言して使うことができる。

委譲とプロトタイプチェーン

JavaScriptのプロトタイプチェーンでおなじみの考え方。「オブジェクトが自分自身で備えていない特性(機能)を、別のオブジェクトにお願い(委譲)する」ことでオブジェクト指向を実現する。
クラスからオブジェクトを量産するのではなく、あるメソッドを別のオブジェクトに関連づけて実行させることができる。
後日注記:プロトタイプチェーンでは、オブジェクトのプロトタイプをプラモデルを作るかのように作成し、そのプロトタイプからオブジェクトを量産する。ここで、あるメソッドをそれが含まれているクラスのオブジェクトだけではなく、別のクラスのオブジェクトにも適用できる。これを委譲と言う。

リフレクション

リフレクションは、プログラムコード自体の構造や情報にプログラムから動的にアクセスする機能。
たとえば、文字列からメソッド名を読み取って動的に異なるメソッドを実行したり、プログラム内のメソッドの定義情報にアクセスしたり、メソッドの定義情報を変えたり、プログラムコードを書き換えたり、時にはプログラムコード自体を実行中に組み立てて実行したりすることができる。
リフレクションは、JavaRubyのようなインタプリタ式の言語においてサポートされていることが多い。リフレクションがサポートされている言語では、デバッガやIDE統合開発環境)を容易に作りやすくなる。
C言語のようなコンパイラ式の言語では、コンパイルした時点でもともとの関数定義情報などが失われてしまう。しかしながら、GCCなどの多くのCコンパイラでは、DEBUGビルドをサポートしており、コンパイル時にデバッグのためのシンボル情報を付加することで、gdbなどのデバッガでデバッグを行うことができる。
「プログラムもデータである」ということが良く分かる。

シリアライズ

シリアライズ(直列化)は、オブジェクトをそのままデータに保存する技術。
オブジェクト指向においては、ある環境において存在しているオブジェクトを、バイト列やXMLフォーマットに変換することで「オブジェクトをファイルに読み書きする」ことを指す。
たとえば、配列の情報をそのままファイルに書き出し、そのファイルを読み込んで配列を構築したい場合などに使う。
MicrosoftMFCなどでは、シリアライズは一般的なファイルの読み書き技術である。また、JavaPythonなどでもサポートされている。

データの永続化

データの永続化とは、データをメモリ上から不揮発性(電源を切っても消えない)の記憶装置に格納することを指す。
オブジェクト指向においては、データとはオブジェクトのこと。
特に、ユーザーから送られたデータなどが、プログラムと一緒にメモリ上にある場合、永続化を行うことでプログラムが終了してもそのデータが永続的に存続する。
後日注記:単純に永続化するだけならば、オブジェクトをそのままシリアライズして、データファイルに書き出せばいい。実際、この方式はクライアントでもサーバーでもよく使われる。だが、大量の顧客データを扱う場合などに、パフォーマンスや信頼性を考えて、永続化ストレージにはリレーショナルデータベースを用いることが多い。この時、JavaのクラスとリレーショナルデータベースシステムのSQL文を相互に変換し、マッピングするHibernateのようなO/Rマッピングツールが存在する。(しかしながら、Javaオブジェクト指向SQLを変換するO/Rマッピングは、「それぞれ全く異なるもの」であるためよく嫌われている。また、永続化のコードは「SQLからPHPでHTMLを変換してリスト表示する」のようなプログラムになるため、よくプログラマから嫌われている。)

HibernateO/Rマッピング

Javaでの永続化の関連技術に、Java Persistence API (JPA)やJPAの実装であるHibernateがある。Hibernateは「O/Rマッピング」を行うためのツールで、O/Rマッピングとはオブジェクト指向とリレーショナルデータベースシステムの溝を埋めるための技術。
JavaクラスとSQLテーブルの変換を行うにはマッピングデータが必要だが、HibernateではXMLアノテーションXDocletなどが用意されている。

関数型プログラミング

関数型プログラミングとは

関数型プログラミングとは、LispHaskell、MLなどの関数型プログラミング言語にみられる考え方。
関数型言語では文よりも式を重視する。全ての記述が文ではなく式として扱われる。
関数型プログラミングでは、関数は第一級の身分を持つ。
関数型プログラミングでは、mapなどの関数を引数にとる関数を多く使う。これは、「高階関数」と呼ばれる。
また、多くの関数型言語では、変数は代入ではなく束縛されるため、基本的に値を変更することができない。
関数型言語では、繰り返しは手続き的なfor文ではなく、再帰関数を用いる。
そして、イテレータクロージャ・無名関数(ラムダ計算)といった関数型言語特有の言語機能を提供する。

純粋関数型言語

また、純粋関数型言語では、式や関数が評価される時に、副作用が生まれない。
副作用とは、参照している状態を破壊するという意味。
また、「同じ条件を与えれば必ず同じ結果が返る」「他のいかなる機能の結果にも影響を与えない」という性質を「参照透過性」という。

再帰

関数型言語などで使われる関数の再帰的呼び出しの方法。
自分の中で自分を呼び出す関数のことを言う。「関数の中でその関数を呼び出す」ことを呼ぶ、と言うのが定義らしい。
Lispなどで計算する時に、良く使われる。
僕も昔は再帰処理を書くのが好きだった。
オブジェクト指向、ポインタ、再帰は、プログラムを書く時の三大重要概念だと僕は思っています(ビル・ジョイがポインタと再帰の重要性について言っていました)。出来れば使いこなせることが望ましいでしょう。

再帰とfor文の比較

以下は自分で書いたコード。
再帰を使う場合:

int value[10];
    
int funcA(int x)
{
    static int i = 0;
    
    value[i] = x;
    i++;
    
    if (i >= 10) {
        return 0;
    } else {
        funcA(x + 10);
    }
}
int main()
{
    funcA(1);
}

for文を使う場合:

int value[10];

int main()
{
    int i = 0;
    int x = 1;
    for (i = 0; i >= 10; i++) {
        value[i] = x;
        x = x + 10;
    }
}

「値を変えて同じルーチンを繰り返す」という意味では、for文のブロックと再帰関数は変わらない。
funcA関数では、関数を繰り返し実行してもローカル変数iを静的に保持するために、static宣言をつけている。
繰り返し処理を行うには、これら「for文による反復」と「再帰」以外に、イテレータ(反復子)を使う方法がある。大規模なプログラミングでは、イテレータを使ってプログラムを記述することもある。

for (Iterator i = c.iterator(); i.hasNext();) {
    i.next();
    i.remove();
}

S式

Lispでプログラムを書く時に記述する文章の形式をS式と言います。特に、(lisp (lisp lisp (lisp lisp)))のように、「カッコの中にいくらでもカッコが出来る」のが特徴です。

イテレータ(反復子)とジェネレータ(yield)

C++STLJavaPythonRubyなどの多くの言語が提供している機能として、「イテレータ(反復子)」というものがある。
これは、配列やコレクション、コンテナなどの各要素に対して、順にアクセスするための機能。
イテレータを取得して、next()などの関数を呼び出すことで、ひとつひとつの要素に順にアクセスできる。言語によってはfor文で使うこともできる。
また、イテレータと対応して使われることが多いのが、ジェネレータ。これはPythonC#ではyieldと呼ばれるreturnと良く似たキーワードで行うことができる。一回の繰り返しに対して、一回の「yieldまでの処理」が行われる。よって、イテレータを一回実行すれば、ジェネレータ関数(yieldが記述された関数をジェネレータ関数と呼ぶ)が一回分実行される。
後日注記:ジェネレータとは「生産するもの」といった意味ですが、要するにfor文で反復する要素をyieldで「ひとつひとつ生み出す」ことができるのです。

イテレータは反復処理のカプセル化

僕は、イテレータの面白い点は、イテレータのインターフェースを実装したクラスは、共通の反復インターフェースから操作できる、というところにあると思う。
イテレータは単純な反復処理のためにも使えるが、イテレータのインターフェースを実装したクラスを自分で記述することで、「自分独自のイテレータ」を作ることができる。
この時、反復処理の内容で何をやるかは、クラスを作る側の自由。よって、とても高度で複雑な処理を、反復処理の中ですることができる。一見反復処理とは全く異なる処理であっても、イテレータインターフェースが実装されていれば、言語によってはfor文などからそのクラスを利用できる。
僕は、イテレータは反復処理のカプセル化と言えると思う。実装の詳細を知らなくても、共通の繰り返しインターフェースから、あらゆる拡張イテレータを操作できるのである。
また、イテレータの中で使うことができるのが、yield returnすなわちジェネレータである。C#Pythonなどで使えるこの機能は、for文からreturnと同じように値を返すことができるが、一回きりで終わりになるのではなく、繰り返し処理の中でひとつひとつ要素を「生み出す」ことができる。
イテレータとジェネレータを上手く使うことで、どんなデータでも反復処理、すなわち繰り返し処理が簡単にできる。これはfor文やwhile文の「構造化プログラミング」よりも先の「イテレータプログラミング」であると言えると思う。
後日注記:僕は、C#Pythonのジェネレータの良い点は、「言語機能であるfor文と特定のクラスであるイテレータとジェネレータを統合した」ということにあると思う。標準の組み込みのfor文で、繰り返し関数を応用的にインターフェース化し、再利用した。これこそ、オブジェクト指向プログラミングの真価の発揮ではないかと思う。

順番を自由に吐き出せ、繰り返しの数列と処理を分離できる

イテレータは「全ての要素に対して順番に処理する」ことのできる機能ですが、全ての要素をどのように作り出し、そしてどのような順番をその順番とするかは、プログラマに任されています。
そのため、たとえばジェネレータを使って「素数の一覧オブジェクト」を作って、順番に処理する際に素数をひとつひとつ「作り出す」ように反復させることもできます。
また、イテレータを使うことで、繰り返しの数列と処理を分離できます。反復して要素を作成する処理はデータベースの機能を使って、表示処理をHTMLへの出力としたりすることが可能です。

クロージャと無名関数

クロージャは、「自分を囲むスコープにある変数を参照できる関数」のことで、JavaScriptRubyでおなじみの、関数を定義したスコープにある変数を使用できる関数のこと。
Lispのような関数型言語の考え方である。上手く使うことで、簡易オブジェクト指向(さまざまな関数から共通のデータを参照する)のような使い方もできる。
一部の言語では、クロージャを無名関数やラムダ式で行っている。無名関数は、昔デリゲートなどと呼ばれてC#などで提供されていたこともあり、C#ではWindows.Formsのイベントにメソッドを登録する際に無名関数は便利である。

並列性と制御モデル

並列性とは

並列性とは、UNIXのようなマルチタスクのOSにおいて、複数のプログラムや処理を同時に(並列して)動かすことのできる仕組み。
単純で開発しやすいモデルは、UNIXコマンドラインシェルから実行されるプログラムのように、「小さなプログラム」がたくさんあって、そのプログラムを複数同時に実行させる、「プロセス」と呼ばれるモデル。
プロセスは、単に小さなプログラムを開発し、OSの側が並列で実行させるため、シンプルで、開発もしやすいが、同時に実行されるプロセス同士がどのように通信し合うか(プロセス間通信やCORBA/D-Busなどを使うことはできる)という課題がある。また、プロセスを作成・破棄させるためにオーバーヘッドが大きいという問題もある。
これに対して、ひとつのプロセスの中で、関数レベルで処理を並列実行させる「スレッド」と呼ばれる仕組みもある。これはオーバーヘッドも少なくパフォーマンスが向上するため、ApacheJavaサーブレットなどのサーバーソフトウェアで多く採用されている。また、プログラムの中で、それぞれのスレッドが同じ情報にアクセスして通信し合うことも容易である。だが、同じデータに同時にアクセスしたり、読み書きを同時にしたりした時に、データに矛盾や破損が起きないように、ロックをかけて排他制御して「スレッドセーフ」な関数にする必要がある。
後日注記:実際のところ、プロセスとスレッドの大きな違いは、プロセスはそれぞれのプロセスに独立したメモリ空間を持つが、スレッドはひとつのプロセスの中で同じメモリ空間を各スレッドが共有する、ということ。また、プロセスは独立性が高いため、ひとつのプロセスが破壊しても別のプロセスに影響はでないが、スレッドでは同時に破壊されてしまう。スレッドの場合は同じデータを同時に読み書きすることで破壊される恐れがあるため、排他制御やロックを用いてスレッドセーフな関数にする必要がある。また、プロセスにおいても共有メモリによってメモリ空間を共有する(独立メモリと別に共有メモリを持つ)ことはできる。OracleなどのDBでは、キャッシュや表や索引など多くのデータを各DBプロセスが共有している。

UNIXと並列処理

ある意味、UNIX系のOSは、こうした「並列実行」がとても得意で、タスクをたくさん実行させても、落ちることなく負荷が高くなっても正常に実行し続ける。これはひとえにUNIXカーネルとユーザーランドを分ける仕組みが安全であるからである。たとえば、UNIXではプログラムはハードウェアに直接アクセスすることは基本的にできず、カーネルを介す必要があるが、DOSではユーザーランドのプログラムがハードウェアに直接アクセスできる。UNIXは安全なやり方を提供するが、その代わり融通が利かないところがあり、DOSの方がゲームなどは作りやすい。また、歴史的にUNIXカーネルパブリックドメインで開発されており、「とても枯れた技術」であるため、簡単には壊れない「長年の蓄積」があると言える。これはBSDソケットなどのネットワークインターフェースシステムについても言え、UNIXには長年のネットワークの経験の蓄積がある。

イベント駆動とは

イベント駆動とは、「外部の環境から何らかのイベントが伝えられて、そのイベントに応答する形でプログラムを書く」こと。
Linuxカーネルのように、全てのプログラムのベースとなる環境的なプログラムや、Windows APIのように外部のメッセージの通信によって、ユーザーのハードウェア操作や中心となるウィンドウシステムの命令に応答するプログラムでは、形こそ違えど、このイベント駆動と呼ばれる制御モデルを設計の中心としている。
Linuxカーネルは、自分から何もしないプログラムで、ソフトウェアのシステムコール呼び出しやハードウェアの割り込みに対して、応答することでしか処理が行われない。これはNginxのようなサーバーデーモンや、コマンドラインシェルやインタープリタなどにも似ているスタイルである。
また、GUIのウィンドウアプリケーションでは、一言にイベント駆動といっても、何種類かのやり方の違いがある。ひとつは、XlibやWindows APIやSwingのリスナのように、イベントが常に送られてきて、次のイベントが送られてくる間隔をループし、メッセージループでそのイベントメッセージを処理するという方式。もうひとつは、そうしたメッセージループをフレームワークが行い、ユーザーはイベントハンドラやコールバック関数をウィジェットに登録し、自動的にメッセージがやり取りされるようにする方式(これを指してイベント駆動とかイベントドリブンと呼ぶこともある)。他にも、MFCのようにメッセージマップに対応するクラスライブラリのメソッドを継承・オーバーライドする方式などがある。
イベント駆動のプログラムは、えてして巨大化しやすい。巨大化すると小さな環境で動かないこともあり、開発の困難さも増え、軽量さやパフォーマンスも落ちる。特に、これがマイクロカーネルなどといったさらに高度なプログラムになると、開発が破綻してしまう。Linuxカーネルでは、モジュールを実行時に動的に追加・削除できるようなモジュラー化のスタイルを取りながら、不要な機能は必要に応じて削除できるようにし、マイクロカーネルではなくモノリシックカーネルの方式をとることで、開発を単純にし、パフォーマンスを向上させている。

Windowsとイベント駆動

こうした「イベント駆動」については、長い間コマンドラインインターフェースを取ってきたUNIXよりも、Windowsに軍配が上がる。
UNIXでは、X11を使う場合であってもコマンド操作が中心となるため、「万人が操作しやすいGUIインターフェースを作る」ということがおろそかになってきた。それはコマンドラインの優れた機能、grep/sed/awkやコマンドのオプションやシェルスクリプトなどを使いこなすことで、簡単に自動で処理を行うことができる、というメリットが、逆に初心者や一般ユーザー向けのことを考えてこなかったということの結果である。
アラン・ケイダイナブック構想からMacintoshWindowsに繋がる、「GUIによる仕事用のインターフェース」というモデルは、そもそもUNIXは取ってこなかった。逆に、Windowsにおいては、多くのプログラムが単純な「マウスやキーボードへの応答」となってしまい、グラフィックスやインタラクティブな操作による直感性と使いやすさはあるものの、バッチ処理による自動化やスクリプティングのことは考えられていない。多くの場合スクリプトは記述できず、手作業で操作を行わなければファイルやテキストの編集はできない。アプリケーションの機能や重さも大きく肥大化する傾向にあり、不正終了やフリーズも多い。また、ひとつのアプリケーションがシンプルなスタイルをとっておらず、複雑怪奇であるため、バグも多く、開発も困難を極める。(だが、Windowsについて言えばインターネット上のフリーソフトは豊富に存在し、テキスト処理を行うのであれば、サクラエディタなどのサードパーティフリーソフトを使うことで何とかできる場合もある。)
UNIXコマンドラインプログラムであれば、単純なプログラムとなり、枯れた技術でもあるためバグの入り込む余地が少なく、ひとつの「カーネル」の上で小さなプログラムが動くというシンプルなスタイルから安定しており、信頼性が高い。そのため、データベースやネットワークサーバーなどの高信頼性や高いスループレットが必要な処理では、UNIXのようなコマンドラインのOSが今でも使われるのである。
ある意味、Windowsは「仕事用で使う真面目な目的のためのゲーム」のようなものであると考えられる。ディスプレイに表示されるウィンドウと、マウスやキーボードによるイベント駆動が、ゲームのコントローラと似ているからである。逆に、UNIXは計算処理をたくさんさせるための「昔ながらのバッチ処理インターフェース」であると考えられる。Windowsは使っていて面白いが、UNIXは目的がなければ何の面白さもないだろう。
また、最近はLinuxにおいても、Windowsと同様のGNOMEKDEのようなGUI環境が増えてきた。確かにWindows並みに使えるものにはなっているが、僕はこれらについてはまだまだであると思う。Windowsと似通った独自性のないインターフェースになっているし、Windowsと同程度にバグが多く、また解決が難しい不具合が多くみられ(特に日本語環境)、情報にありつける頻度は極端に少ない。こうした分野でWindowsと同じものを目指してはいるものの、まだまだ未完成品であると評価せざるを得ない。だが、一部のマニアックなオタクにおいては、Windowsとは違う「オープンソースLinuxデスクトップ」として崇拝されており、それが悪いことであるとは思わない。逆に、GNOMEKDEでも、ターミナルエミュレータを使うことはほぼ必須であり、またWindowsとは違って多くのオープンソースソフトウェアが無料でついてくるため、優れた素敵な環境にはなっている。カスタマイズ性も高い。開発環境やUNIXの練習環境、あるいはただの遊び用途であれば、お金を一銭も払わずに導入でき、「みんなでインターネット上で開発していて、自分も参加したい」という、研究・教育用途にはうってつけである。逆に言えば、研究・教育用途以外に、使い道はないだろう。

mutex

以下はCode Reading ~オープンソースから学ぶソフトウェア開発技法~ (プレミアムブックス版)を参考にしています。
複数のスレッドまたはプロセスを操作するときは、共有リソースの扱いが問題になる。
共有グローバルリソースにアクセスするコードでは、排他的なアクセスを設定するための「相互排他」(mutexと呼ばれる)抽象データを定義する。
mutexには、一度に1つのスレッドしかアクセスできない。
mutexにアクセスしようとしたときにmutexがロックされていた場合、ロックが解除されるまで現在のタスクがブロックされる。
タスクは共有リソースにアクセスした後、mutexのロックを解除してほかのタスクに解放する。
したがって、共有グローバルリソースにアクセスするコードには、mutexのロックとロック解除が対の形で現れる。
mutexのコードの例:
1.mutexをロックする
2.処理を行う
3.mutexをロック解除する

アルゴリズム

アルゴリズムとは

アルゴリズムとは、コードブロック(プログラム)の全体の構造や流れのこと。
特に、ソートや探索など、ある目的のために順序立てて作られた、データの整理のプログラムのことを「アルゴリズム」と言うことが多い。
ソートや探索では、一時的な記憶領域(変数)にデータを格納し、繰り返し(反復して)データを移動・変更・書き換えることで、データ全体を順番に整理したり(ソート)、目的のデータを探索したり(探索)する。
場合と条件によって反復的にデータを書き換え、全体の処理が終わった時にきちんとソートができるか、といったところを数学的に考えてコードを作る必要がある。
ソートや探索に限らず、ある目的のためのコードブロックの流れや順番に沿った構造のことをアルゴリズムと呼ぶ。プログラミングは、このアルゴリズムを中心に行う。多くの場合一時的なデータを保管し、反復や条件分岐によって場合や条件を変えて書き換える。

フローチャート

アルゴリズムを自分で設計・実装する場合、条件分岐や反復構造の中で処理の流れを考える、「フローチャート」と呼ばれる図を描くことが、特に初心者にとっても、また上級者にとっても有効です。
実際のところ、数学的なアルゴリズムを自分で開発するのは、とても難しいことです。いきなりコードを描いてできることではありません。
フローチャートを描くことで、いつどのような条件で処理を実行し、実行内容をどのような手順(それも単純ではなく複雑な手順)で実行するのかを考えることができます。
ソートや探索だけではなく、文字列検索やメモリやデータベースなどのリソース管理などに必要なアルゴリズムも、フローチャートを描くことで書きやすくなるでしょう。

与える変数や参照・取得する変数だけを変えて同じルーチンを実行する

アルゴリズムに多いのが、ルーチンワークです。これは、「与える変数や参照・取得する変数だけを変えて同じルーチンを実行する」というものです。
与える変数とは、インクリメントされるカウント変数や、関数やブロックに引数などとして渡す、「一回一回変わるデータの参照先」です。
また、参照・取得する変数とは、データを参照・格納したり、場合によってはソートしたり探索したりする、「保持するデータの格納先」です。
ルーチンを書く時には、こうした変数をどのように捕捉するかを考えながら、どんな場合においても共通の「手順」を書きます。たとえば、ファイルの文字列を一行ごとに検索し、正規表現でマッチするパターンがあればカウントを増やす、あるいは何らかの処理を実行する(マッチした部分と回数のプリント出力など)といったことが記述できます。
そして、条件式やジャンプ命令などで、「この場合に終了する」とか、「この場合は処理を行わず次の処理を行う」などといった「中止命令」を内部に挿入します。場合によっては最後まで処理すれば停止するだけではなく、途中で何らかの文字列が含まれていれば即座にアボートする、などといったことが考えられます。
アルゴリズム」とは、このようなルーチンの設計を指して言わることが多いです。

アルゴリズムを自分で書く場面

最近は、クラスライブラリのようなモジュールが既に用意されていたり、専用のSQLなどのデータベースサーバーがオープンソースで入手できたりすることから、本当にアルゴリズムを自分で書かなければならない場面というのは少なくなっています。
それでも、純粋な数学的記述を行ったり、自分で独自の処理を柔軟に行うために、画像処理やテキスト処理などを自分で独自に実装したり、あるいはハードウェアやバックエンドに近いカーネルファイルシステムやデータベースなどのデータ構造を作ったり、GUIに近いところではHTMLレンダリングエンジンなどのコアのコンポーネントを作ったりするためには、自分でアルゴリズムを設計しなければなりません。
アルゴリズムの設計としてもっとも単純なのは、分岐命令や繰り返し命令を図にし、その図の中にプリントなどの処理や変数の操作を書く、フローチャートです。
また、オブジェクト指向モデリングUML図においては、クラス図やシーケンス図を描くことで、行われる処理と「どのようなデータ構造を使うのか」を明確にし、クラス間の関係性や関連性を考えられます。
オブジェクト指向アルゴリズムを設計するためには、デザインパターンも有効です。デザインパターンは多くの設計に共通する「デザイン上のよくあるパターン」を集めたもので、JavaだけではなくC#Pythonなどでアルゴリズムを書く時も、デザインパターンが参考になります。特にBuilderパターンはよく使われます。
また、アルゴリズムだけではなく、データ構造も重要です。ファイルシステムを実装する場合も、アルゴリズムだけではなく、iノードやダーティビットなどを作る上で、双方向リストなどのようなデータ構造を使ってどのようにアルゴリズムを書くかはとても重要です。スケジューリングやメモリ管理についても、たくさんのアルゴリズムがあると同時に、それと関連するひとつひとつのデータ構造があります。
僕は全然データ構造のこともアルゴリズムのことも詳しくありませんが、「バックエンドの開発でもフロントエンドの開発でもアルゴリズムとデータ構造の知識は必須」であると考えた方が良いでしょう。ライブラリやモジュールに頼るだけのプログラミングから、自分でライブラリやモジュールを書けるプログラミングへとレベルアップできるでしょう。

ハードウェアに近いところにもアルゴリズムはある

アルゴリズムというと、「抽象的で数学的な方法や手順である」とされることが多いですが、実際のプログラミングにおいては、ハードウェアにとても近いところでもアルゴリズムが多くみられます。
たとえば、Linuxカーネルのメモリ管理のアルゴリズムや、CPUスケジューリングのアルゴリズムなどが代表的です。
具体例をひとつ挙げると、CPUスケジューリング・アルゴリズムとして、「ラウンドロビン」と呼ばれるアルゴリズムがあります。これは、実行可能状態にあるプロセスにひとつひとつ順番に交代してプロセッサを割り当てるアルゴリズムです。また、これ以外にもスケジューリングのアルゴリズムはあります。
このように、アルゴリズムは必ずしも数学的ではなく、極めてハードウェアに近い部分でも多く見られます。OSカーネルやバックエンドを学ぶ上では、こうしたアルゴリズムの知識が欠かせません。

独自データベースとアルゴリズム

データベースのようなバックエンドは、アルゴリズムが分かっていると、独自に設計して開発することができます。
これは、たとえばスケーラビリティが必要な場合(クラスタ・スーパーコンピュータからモバイルやゲームまでスケールが大きい・小さい場合に独自に実装する)とか、扱うプラットフォームやシステム構成が特殊だったりする場合や、独自の機能が必要な場合(ネットワークやセキュリティや並列性など)、あるいは信頼性や性能で妥協を許さない場合などに有効だと思います。
実際は僕もやったことがないので分かりませんが、MySQLPostgreSQLでは対応できない状況というのはあるでしょう。
こうした場合にデータベースのインデックスや検索などのアルゴリズムを知っておくと、自社でデータベースに必要な機能を取捨選択することができます。
あるいは、自社でデータセンターを運用したい場合などに、自社でデータベース管理システムを「その決まりや作法に従ったスタイルで」構築したい場合もあると思います。リレーショナルデータベースだけがデータモデルではありません。Amazonなども、AWSのデータベース管理システムをOracleから独自実装に切り替えたと話題になりました。今どうなっているかは知りません。

データ構造

データ構造とは

データ構造とは、プログラムで使われるデータをどのように保管・格納し、どのような順番で要素を追加・取り出しをするか、複数のデータをある一定の順番でどのように連結・管理するか、という「データの構造」のこと。
データの連結の仕方には配列とリストがあり、データの格納・取り出しの順序によってキューとスタックがある。
配列・リストやキュー・スタックに限らず、ある目的のためのデータの構造のことをデータ構造と呼ぶ。どのようにデータを保管するか、どのようにデータを書き換え取り出すかという、プログラミングはアルゴリズムとデータ構造で成り立っている。

データ構造はプログラミングの色んなところで活躍する

僕もあまり経験がないので分かりませんが、データ構造はプログラミングの色んなところ、いたるところで活躍します。
たとえばLinuxカーネルでも、独自の双方向リストを使ってファイルシステムの内部情報を管理したりしています。
また、コンパイラインタプリタ、メモリ管理などでも、スタックとヒープのデータ構造は必須です。
データベースでは、Bツリーと呼ばれる独自のインデックス構造によって、高速なデータ検索を実現しています。また、データ構造を自分で独自に設計することは、データベースでも重要です。

クラス図とシーケンス図

データ構造を考える上で参考になるのが、オブジェクト指向モデリングのクラス図とシーケンス図です。
クラス図はクラスごとの属性や関係性、シーケンス図は処理の流れを時系列にして、図にしたものです。

E-R図

また、データベースにおいてはE-R図を描くことで、エンティティ(実体)とリレーションシップ(関連)の関係性を図にすることができます。

劣ったエンジニアはコードに悩むが、優れたエンジニアはデータ構造に悩む

データ構造について言えることとして、「劣ったエンジニアはコードに悩むが、優れたエンジニアはデータ構造に悩む」というのが言えます。
実際のところ、プログラムとはデータを扱う手続き・操作・処理にすぎません。プログラムで悩むのではなく、データ構造をどうすれば良いかを考えることこそ、コードを書く上で、プログラマには必要なのです。

3D・ゲーム

OpenGLでゲームを作るコツは、座標変換と配置と移動

僕は、OpenGLで3Dのゲームを作るコツは、座標変換と配置と移動ではないかと思います。
たとえば、マリオカートのようなレースゲームを作る場合、まずコースやマップを作り、その上でコースの上にキャラクターを「配置」し、その上でプレイヤーの操作に応じて、キャラクターを「移動」させなければなりません。
OpenGLには、座標変換の機能が多数あります。こうした座標変換の機能を使ったり、ワールドとキャラクターの3DCGの合成を行うことで、配置や移動を行います。また、同じキャラクターやワールドを別の角度から視認することもできます。
僕は、ゲームを作るコツは、座標変換の機能を上手く使いながら、3DCGの配置と移動をどのようにし、どのように合成するか、ということではないかと思います。
そして、それ以上はデザインの問題になります。OpenGLではテクスチャと頂点によるポリゴンの描写が可能で、Blenderなどの3Dモデリングソフトウェアを用いてポリゴンを作ることができます。
後日注記:3DCGを合成することで絵を配置することはできますが、実際には周りの場所と調和した見た目にしなければなりません。こうした時にシェーダを使うのではないかと、僕は勝手に思っています(実際は違うと思います)。

ctags

ctagsがなければ投げ出してしまうかも

ctagsは、ソースファイルやヘッダファイルのインデックスを作って、エディタなどから関数やクラスなどの定義にジャンプすることができるソフトウェアです。
たとえば、「C/C++の勉強したから、いっそClang/LLVMの開発でもやってみるか!」と思い立った時、githubから以下のようなリポジトリを見て、ソースファイルを読んでみようと思ったとします。

そして、ソースファイルを見てみましょう。すると、#includeにヘッダファイルが山のようにあって、その下では見知らぬ関数やクラスが実行されています。
これを見て、「なんだ、こんなにヘッダファイルがある中から、自分で関数定義を探さなければいけないのか…」とあなたは落ち込み、「これは無理だ」と思って投げだすのではないでしょうか。
こんな時、ctagsがあれば、プログラマになる道を投げ出さなくてすみます。

ctagsとは

ctagsは、プログラムの中のソースファイルやヘッダファイルのインデックスを作って、「関数を使っているところ」から「関数の元々の定義」にジャンプすることのできるソフトウェアです。
ctagsがあれば、vimemacsから「なんだこの関数」と思った時に瞬時にその定義を参照することができます。
言ってしまえば、「コンパイラテキストエディタ+ctags=きちんとできる入門者向けの開発環境」であると言えるでしょう。

ctagsという名前ながらたくさんの言語に対応

また、ctagsはctagsという名前ながらたくさんのプログラミング言語に対応し、それぞれの言語に異なるtagsファイルを作成することができる。

デバッガ

「何がどこで実行中か」を見ながら作る

ある意味、プログラムの基本とは、「何がどこで実行中か」ということがポイントだと思います。
いつ、そのプログラムがどこで何を実行しているのか、それが分かると、たとえばループの条件判断に関数を入れ込むなど、といった荒業でプログラムを書くことができます。

バグのないプログラム

僕は、パソコンのプログラムを開発するという仕事は、たくさんの部品を組み合わせて作る自動車などとよく似ていると思います。
自動車の製造過程では、それぞれの部品が上手く働くかを入念にテストし、きちんと動く部品だけを組み合わせて全体の自動車を組み立てます。
プログラムもこれと同じで、入念にそれぞれのモジュールやコンポーネントをテストして、バグのないプログラムを作ることができます。
ですが、プログラムという特性上、きちんとプログラムが動くかどうかをテストするのは難しいものです。たとえば、入出力だけをテストしても、内部のデータ変数全てが適切に働いているかどうかをチェックすることは、デバッガを使わないとできず、またデバッガを使っても難しいです。
それから、プログラムはアナログな部品と違って、とても多くの実行パターンを考えなければなりません。画像処理であればあらゆるグラフィック処理の全ての場合を考えなければなりませんし、コンパイラインタープリタであれば、あらゆる言語的記述の全ての場合を考えなければなりません。
ここで、一番簡単にできるのは、もし金儲けを考えない場合であれば、オープンソースにして、みんなでプログラムにバグがないかをチェックする、という方法です。
よって、僕はオープンソースは、自動車などの製造で巧みな技術を持っている日本の製造業に親和性が高いと思います。同時に、日本がきちんとしたテスト用のフレームワークを作れば、オープンソースにしなくても、同程度の高品質のプログラム開発を行うことは可能ではないかと思います。
デバッガを使うことで、ある程度のプログラムのコード分析を行うことができます。値をその時のブレークポイントでチェックしたり、変数にさまざまな値を代入してテストすることができます。printfチェックなども併用しながら、プログラムにバグが混入しないように注意して開発しましょう。
最近は、Windowsなどの開発も高度になってきており、.NETなどの新技術も使いながら、たくさんの資金を投入して安定したOSをMSも作っています。以前のように「Windowsは不安定だがUNIXは安定している」とは必ずしも言えなくなっています。特に最近はLinuxでもGUIの巨大デスクトップ環境を開発しており、Windowsと同じぐらいバグがあります。特にオープンソースでは、きちんとテストされているかどうかは不透明で、保証もなく、また一部ではアマチュアプログラマがコードを書いていたりして、必ずしもオープンソースは高品質ではなくなっています。
後日注記:実際には、オープンソースにするだけでバグがなくなるということはなく、プログラマによる設計と実装が重要になる。たとえば、コアの関数を正しく書き、どの処理でもその関数を使うようにすれば、バグの入る余地を減らすことができる。また、たくさんの処理が増えすぎた時は、全てのコードを書き直す必要もある。これは仕事でプログラミングを書く時にも言えて、バグが解決できない時はもう一度全て書き直すしかない。これがそのまま「デスマーチ」へと繋がるのである。

ユニットテスト

ユニットテストとは

JavaC/C++でプログラムを書いて、コンパイルエラーが出ることなく、プログラムを実行して不正終了もなかったからといって、そのプログラムにバグや誤動作が無いとは限りません。
プログラムを実行して、その実行した結果が正常だったからといって、別の条件で実行した時は、果たしてプログラムは期待通り動くでしょうか?
バグを修正する手助けとなる、ブレークポイントやステップ実行のできる「デバッガ」は、あくまで、バグを見つけてそのバグを直すものであり、「プログラムの実行の結果にバグがあるかどうか」までは判断してくれません。
このような時に、ひとつでも多く不正終了や誤動作を検出するために、「テスト」が重要になります。ユニットテストをするとプログラムの品質が上がります。

開発手法

ウォーターフォール

基本計画、外部設計、内部設計、プログラム設計、プログラミング、テストの各工程(フェーズ)を順に進めていく手法。
ソフトウェア会社で行われるもっともポピュラーで古典的な開発手法。
全体を見通しやすく、スケジュールの決定や資源配分が容易に出来るほか、システム開発の一貫性がある。だが、システムの完成イメージを見ることが出来るのは最終工程になってからであり、後戻りをすることが出来ないため、要求仕様の変更に対応することが難しい。

アジャイルエクストリーム・プログラミング

迅速かつ適応的にソフトウェアを開発する。ウォーターフォールモデルでは段階的にひとつひとつの工程に従って開発するため、前の工程に戻ってやり直しをしたりすることが難しい。アジャイルでは柔軟かつ短いサイクルで反復的にソフトウェアを開発する。アジャイルの代表的な開発方法にエクストリーム・プログラミング(XP)がある。

ペアプログラミング

2人のプログラマがペアとなってプログラミングを行うこと。

リファクタリング

プログラムの外部から見た見た目を変えずに、ソースコードの内容を整理すること。

オープンソース開発

バザール開発

オープンソースの開発手法について述べられた文書と言えば、エリック・レイモンドによる「伽藍とバザール」が有名です。
ここでは、GNUによるHurdの開発のような、少人数のコアチームだけが慎重に開発していく開発プロジェクト管理の方法を「伽藍」(キリスト教でいう教会のようなもの)と呼び、Linuxカーネルのような「乱交まがいにどんどんみんなからの成果をとり入れ、全ての情報を全員に公開し、しょっちゅうリリースする」という「Linuxにおける革新的な方法」を「バザール」と呼びます。
また、エリック・レイモンド自身も、Fetchmailという自分のプロジェクトにバザール開発モデルをとり入れて、大成功を収めました。

エリック・レイモンドの文書では、「ハッカーになろう」が面白い。

Mozilla.orgの失敗

この伽藍とバザールをきっかけに、ブラウザ戦争で敗北したNetscapeが、自社のNetscapeブラウザの存続のためにブラウザをオープンソースにした「Mozilla.org」が生まれました。しかし、ここでは、Mozilla.orgを率いていたNetscapeのエンジニアだったジェイミー・ザウィンスキーが、Mozilla.orgプロジェクトの停滞から、「辞職および追悼」という文章で「オープンソースは魔法のお鍋ではない」と記述したことも有名です。

オープン開発

オープンソースプロジェクトを始めるにあたって、企業とコミュニティがどのように連携するか、という点が重要になってきます。
まず、単なる個人プロジェクトなら、オープンソースにしても問題が起きることは少ないでしょう。ライセンスがGPLであれBSDであれ、Anthyのような「完全にコミュニティのソフトウェア」であれば、それはWindowsでおけるフリーソフトの開発と同様にひとりで全て開発することもできますし、パッチなどを提供されれば取り入れることもでき、OpenJaneのように協力して開発する時も、それぞれの個人が「完全に自由に関わり合う」中で「自発的に共有」すれば、それで簡単にコミュニティ開発ができます。
ですが、企業の中でコミュニティ開発を取り入れることは、それと比べて少し難しいでしょう。どこからどこまでを社員が開発し、コミュニティとどのように関わり合うのか、それをきちんとすることは難しく、上に書いたMozilla.orgのように、「ほとんどNetscapeの社員だけが開発していた」という状況になりかねません。
ここで参考になるのは、はてなのような「草の根ベンチャー企業」です。はてなはブログやブックマークなどのWebサービスを開発する会社ですが、そのサービスの機能ややっていることについて、公式のブログなどで提案や意見を取り入れています。以前は、「はてなアイデア」のようなアイデア共有サービスや、「はてなLab」のような研究中のサービスをベータ公開するサービスもやっていました。
Red HatGoogleのように「どんどんオープンソースコミュニティをリードしていく会社」になることは難しいかもしれません。ですが、ユーザーからの改善や意見を取り入れていく、という意味では、オープンな開発も今からのネット社会で有益な立場を保っていくでしょう。何もオープンソースに限ったことではないと思います。

オープンソースの理想

2019-08-19より。
人を騙すな。不当に支配するな。不当に抑圧するな。
自分の私利私欲のために、善良な集団を利用するな。
悪を許すな。悪はいつでも、勝手にこの世界を利用して、悪いことをする。そのような悪いことをするものを許してはならない。
善良なものが、善良であり続けるために、努力せよ。
平和とは、透明性が保たれていて、みんなが正しいことをしている、ということが、誰の目に見ても明らかでない限り、訪れないものだ。
ナチのように、心理学で人を支配するな。努力しているものたちの上に、馬鹿な指導者が就いてはならない。
人々を公平に、平等かつオープンな思想の下、自由にせよ。それぞれが、独自のやり方で、独自の手段で、独自のプロジェクトを、独自に実行し、それぞれのやりたいようにし、そのための共有のルールを明確化し、透明性が保たれるようにせよ。
自由な参加を許し、秘密を隠すな。自分だけが良い思いをして、みんなに隠した上でひそかに支配するようなことを絶対にしてはならない。
迷った時は、全員に意見を求めよ。自分の思ったこと、悪いと思ったことやそうでない方が良いのではないかと思ったことを、率直に、素直に言えるようにし、そのための場を設けよ。
人々が、あらゆる大切なこと、プロジェクト管理のようなことを、話し合う場を作れ。それぞれのやり方を尊重すると同時に、他人が不当に行動を制限されたりするようなことが無いようにせよ。
分かっていないものは、分かっているものを尊敬し、また分かっているものは、分かっていないものが間違ったことをしないようにせよ。
プロジェクトが自分の責任で間違った方向に向かおうとしている時には、それをきちんとみんなに伝えて、正しい方法でプロジェクトの方向が修正されるようにせよ。
無計画に行うな。無知のまま教えるな。未来の方向が分からない方向に向かうことがないようにせよ。「みんなが分からなくなる」ということを絶対に避けよ。誰かひとりにしか分からないなら、そのひとりの分かっていることを、正直にみんなに伝え、みんなが分かるようにせよ。
そのようにしていけば、きちんと正常な世界になる。オープンソースとは、そういうことである。オープンソースが正常であるためには、公平で、誠実で、透明性があり、間違った方向に向かわず、秘密を作らないことが必要だ。

オープンソースの意味

僕は、オープンソースの意味とは、「自分の分からないことでも、他人が見て分かることがある」ということではないかと思う。
たとえば、自分の欲しくなかった機能や、自分が見つけられなかったバグも、他の人が機能を付けたり、バグを直したり、ということができる。
だが、先に書いたように、誰かひとりのわがままが、全員の努力よりも不公平に優遇されたり、不当に支配されたり、あるいは秘密として隠されたりすることがあってはならない。
会社による開発ではなく、オープンソースによる開発は、インターネットを使うという性質上、さまざまな人が関わり合う。だから、秘密を無くして透明性を保ち、より公平にしなければならない。

共有という名の奇跡

オープンソースは、まさに「共有という名の奇跡」です。人々が自発的に取り組み、助け合い、協力し、そこで成果を「共有」すること、それそのものが楽しく、また技術的にも一流のOSになりました。
OSはさまざまなプログラムによって共有されるプログラムであり、それ自体がたくさんのコラボレーションの中で共有されることと親和性が高いのです。これはWorld Wide Webにも言えることです。
Sunが「ネットワークこそがコンピュータである」と言いましたが、僕は「共有こそがコンピュータである」と言いたいです。コンピュータは資本主義の会社によって閉じられたものではなく、広く一般に公開され、共有されるべきなのです。MicrosoftIBMは賢い会社ですが、そうした共有の文化には適応できなかったのです。
こうした「共有こそがコンピュータである」といった考え方は、アメリカの会社よりも日本の会社の方が良く適応できていると僕は思います。たとえば、はてなは質問サイトやブックマークなど、早くから「人力による共有」を目指してきました。アメリカが、ロボットやAIなど全ての人間の力を自動化しようとしているのとは対照的に、日本の会社はみんなが一堂に会する「ネットの共有プレース」に目をつけ、たくさんの「手動の人力の共有」を行うことで、サービスを作り出しました。こうした発想は、アメリカの会社にはないものです。FacebookすらAIをやっていますが、僕は「AIによる自動収集」に打ち勝つのは、「ネットワークというたくさんの人々が繋がった上での、それぞれの成果の共有」だと思います。オープンソースは、そもそもが、そうした会社による高度な自動化技術とは対照的で根本から異なるものなのです。
そう、コンピュータとは人工知能のように、人間の頭脳を再現し、人間による成果を省力化する技術でもありますが、ネットワークは人間と人間を繋げるものであり、それぞれの些細なことであっても、共有することで爆発的なエフェクトを作り出すのです。人間がAIに負けるのか、それとも人間の共有の力をネットワークが引き出すのか、人類と人間の新しいバトルがここに始まるでしょう。
後日注記:ある意味、最近のIT業界は「人間に代わるもの」を目指そうとしているが、僕は「人間を活かすもの(あるいは場所)」を作らなければならないと思う。人間が共有スペースを手にいれることで、さまざまなことが可能になり、可能性が高まり、発想が豊かになる、ITサービスはそういうものでなければならない。

簡単な説明

プログラミングの基本

  • プログラミングの基本
    • 考え方
      • コアルーチンを作る
      • モジュールやライブラリを使う、自分で作って分ける
      • システムレイヤーを分ける
      • データを操作する専用のインターフェースを作る
      • コマンドラインオプションによる条件分岐
      • イベント駆動
      • テキスト処理
      • ファイル処理
      • IO
      • ネットワーク
        • ソケット
        • サーバー・クライアント
        • CGI
      • パターンマッチングとテキスト整形
      • エラーハンドリング
      • 科学計算
      • ゲーム、マルチメディア
    • 制御フロー
      • 条件分岐
      • 繰り返し
      • 関数
        • 定型ルーチンをまとめる
        • 引数
        • 戻り値
        • 汎用的な利用
      • フローチャート

データ構造とアルゴリズム

  • データ構造とアルゴリズム
    • データ構造
      • データ型
        • int型
        • char型
        • float型
        • double型
        • const
        • static
      • 配列
      • 構造体
      • スタック
        • 上に積んでいって、上から取り出す感覚
        • プッシュ
        • ポップ
      • キュー
        • 横に行列が並んで、一番長く並んだ人から受け取る感覚
        • エンキュー
        • デキュー
      • 配列とリスト
        • 双方向リスト
        • 環状リスト
      • ハッシュ
      • ツリー
        • ツリー構造のデータ構造
        • 二分木
        • ヒープ
        • B-Tree
          • 二分探索を行うために、最初から探索をしやすいようにツリーの構造を作る
      • グラフ
        • ノードとノードが繋がるデータ構造
    • アルゴリズム
      • 探索
      • ソート
      • ハッシュテーブル
        • 配列の中に各リストへのポインタを格納する
      • ハードウェアやバックエンドに近い低レベルレイヤーでのアルゴリズム

ポインタ

  • ポインタ
    • ポインタ
      • 参照としての利用
      • ポインタの引数
        • ポインタの引数を使うことで、関数の内部から外部の変数を変更できる
      • 動的なメモリ管理
      • 関数ポインタ

関数型プログラミング

オブジェクト指向

並列処理・制御モデル

  • 並列処理
    • プロセス、スレッド
    • 非同期処理
    • 排他制御(ロック)、mutex
  • 制御モデル
    • マスター・スレーブ
      • 主従関係のこと
    • イベント駆動
      • イベント駆動は、イベントを通知してその時に割込み処理を行う
    • ポーリング
      • ポーリングは、待機した状態で定期的に確認して、何かあれば処理を行う
    • メッセージキューイング

プログラミング言語

開発支援ツール

GUIフォームから関数を呼び出す

Adobe製品のようなGUIアプリケーションは開発するのが難しく見えるが、実際はフォームをデザインしてそのフォームから関数を呼び出せば開発できる
大事なのはGUIフォームよりもコア機能を提供するためのコアルーチンの設計

基本

条件分岐

条件分岐はプログラムの基本。どのような「条件の場合」にどのような「処理」を行うかを書く。

繰り返し

ループは単に同じ処理を繰り返すだけではなく、イベントループのように「常にイベントを待ち続ける」とか、「それぞれの場合に処理を適用する」(たとえば正規表現でのパターンマッチングを全ての行に適用する)などのように使うこともある。

関数

関数は設計の基本。汎用的な関数を作り、「共通のコアルーチンを上手く呼び出す」ようにプログラムを設計・実装する。
さまざまなコードの場所から「ライブラリ」のように関数を呼び出したり、「データを処理する時のラッパーインターフェース」として使ったりすることもある。

配列とリスト

配列は連続的に要素が並んで格納されるが、リストは次のデータへポインタを紐づけするようにデータを連結する
配列は検索やアクセスがしやすいが、リストは追加や削除がしやすい

ポインタ

参照としての利用

ラベルを同じ箱を指す別の名前として使用する
変数名ではなく、メモリアドレスによって、絶対的位置から変数を操作する
C言語でリストなどを実装したり、カーネル内部のバッファにアクセスするなどに必要

関数型プログラミング

イテレータ

反復処理を行うための反復子

ジェネレータ

yield returnなどにより、「ひとつひとつの要素をその都度生成する」かのように、for文の繰り返しごとに新しい値を返す

再帰

for文を使うのではなく、関数の内部から「自身の関数を呼び出す」ことで、繰り返しを「引数とreturn」で表現する

オブジェクト指向

オブジェクト指向とは

データへのアクセス保護や、専用のインターフェイスだけを提供し、データにはメソッドを通じてアクセスする
継承により、既存プログラムの再利用や上書き・改良を、既存コードを変更せず、追加で行える
メンバ変数は、メソッドの中で共有される共有財産であると同時に、オブジェクトがその時その時保持する状態となる一時データである
クラス階層はオブジェクト指向でのオブジェクトすなわちものとしてのデータのふるまいと階級を表す

カプセル化

メンバ変数をメソッドのみから操作することでカプセル化する
必ずしもクラスのメンバのメソッドにすることがカプセル化につながるわけではなく、メンバではないメソッドにした方が正しいこともある(メンバを無用意に増やすと逆にカプセル化を破壊する)ので注意しよう

コンストラクタとデストラク

インスタンス作成、破棄の時に、オブジェクトの初期化と後始末を行う
時に効率化の問題(単にオブジェクトを宣言したりコピーしたりした時にコンストラクタやデストラクタが何度も無駄に実行されること)があるので注意して設計しよう

継承

クラスにあとから機能を付け足す

オーバーライド

継承した時に、メソッドの内容を上書きして書き換える

インターフェース

どのようなプログラムでも同じインターフェースから操作できるようにする
たとえばwriteとreadを実装するインターフェースを作れば、どの実装でも同じwriteとreadというAPIから操作できる
よく似たものに抽象メソッドがあるが、これはメソッド呼び出しを先に記述しておき、メソッドの内容だけを後から記述することができる

テンプレート

テンプレートとは、要するに、クラスの中で使う型について、お望みの型が使えるようにする
まるで「型を作る型」のように、たとえばコンテナの場合であれば、コンテナに格納するデータ型の型をその都度指定する
汎用関数や汎用クラスでは、「どんな型が入れられても成り立つように、型を抽象的なTにして記述する」という記述をする

並列処理

プロセスとスレッド

プロセスはひとつひとつ独立したメモリ領域を持つ
スレッドは同じメモリ領域を共有しながら並列処理ができる
プロセスよりもスレッドの方が軽量

排他制御

スレッドセーフな関数を作るためには、別の関数からのアクセスによって壊れる可能性のあるデータは誰かがアクセスする間別の関数からアクセスできないようにロックする

その他の技術要素

eval、リフレクション

リフレクションはクラスや関数の定義情報などを実行時に動的に取得したり書き換えたりする
evalは文字列の内容を式として評価・実行する

シリアライズ

シリアライズはオブジェクトをそのまま読み書きする

永続化、O/Rマッピング

データをプログラムが終了しても再び読み込めるようにメモリの外の領域に書き出す
単純な永続化はシリアライズでも可能だが、パフォーマンスなどを考えてリレーショナルデータベースを使う
O/Rマッピングは、オブジェクト指向のオブジェクトとリレーショナルデータベースのデータを変換するためにマッピングする

開発技法

ウォーターフォール

会社でのシステム開発によく用いられる開発スタイル
「要求定義」「外部設計」「内部設計」「プログラミング」「単体テスト」「結合テスト」「総合テスト」「運用テスト」「運用」となる
途中で前のフェーズに戻ることができないという欠点がある

ctags

関数の呼び出しから関数定義へとジャンプできる
巨大なソースコードを読むためには必須のツール
ちなみにEclipseではF3キーで関数定義にジャンプできる