051.1 レッスン 1
Certificate: |
Open Source Essentials |
---|---|
Version: |
1.0 |
Topic: |
051 ソフトウェアの基礎 |
Objective: |
051.1 ソフトウェア コンポーネント |
Lesson: |
1 of 1 |
はじめに
しばしばFOSS(Free and Open Source Software)と総称される フリーソフトウェア と オープンソフトウェア は、私たちが気づいていないとしても、日常生活に浸透しています。たとえば、インターネットの背後では、何らかの形でFOSSが関わっています。ウェブページを閲覧するブラウザや、ウェブページを保存して呼び出しに応じて提供するウェブサーバーでも、FOSSが関係しています。
ソフトウェア
フリーでオープンなソフトウェア(FOSS)の詳細を検討する前に、ソフトウェア とは何であるかをはっきりさせておきます。一般的な説明から始めましょう。ソフトウェアとは、コンピュータの非物理的・非物質的な部分です。ソフトウェアは、コンピュータの物理的な部分(ハードウェア)を相互に作用させ、コマンドに基づく作業を実行させます。
スマートフォンにせよ、ノートパソコンにせよ、データセンターのサーバーにせよ、電源を切った状態では、金属とプラスチックでできた機械に過ぎません。電源を入れると、コード化された一連のコマンドという形で、ソフトウェアが起動します。ソフトウェアは、マシンを構成している個々の部品を制御し、ユーザーとマシンとの間の入出力を仲介し、アプリケーションによる個別の作業を実行するのです。
コンピュータに実行させたい作業を分析して実装するのが ソフトウェア開発者 の仕事です。ソフトウェアが実行する作業は多種多様ですから、開発者が用いるツールも多種多様です。
ソフトウェアが実行する作業の中には、ハードウェアやコンピュータアーキテクチャと密接に結びついているものがあります。メモリ管理や複数プロセスの処理などがそうです。こうしたハードウェアに近い仕事をする人を、システムプログラマ と呼ぶことがあります。
他方で、アプリケーション開発者 は、ユーザーが効率的かつ直感的に作業を遂行できるように、ユーザーがプログラムを利用する場面に焦点を合わせます。メニューやボタンから文書を整形でき、印刷プレビュー画面を表示できる機能を備えた文書編集プログラム(ワープロソフト)が、その例として挙げられます。
一般に、ソフトウェア開発では、問題を解決するために アルゴリズム を用います。たとえば、平均値を算出するためには、データの合計値をデータの個数で割るというアルゴリズムを用います。アルゴリズムを開発するのはプログラマの仕事ですが、近年では人工知能がアルゴリズムを生成することもあります。
この章のコンセプトは、FOSSの強みと弱みを理解し、合理的な選択をして、さらには自分がソフトウェア開発者になるかどうかを決める手助けをすることです。
プログラミング言語
プログラミング言語 とは、コンピューターに何を行うかを指示するための、高度に構造化された人工言語です。プログラムは通常、テキストで記述しますが、グラフィカルな形式で記述するものもあります。ソフトウェア開発者は、この人工言語でコンピューターに対する指示書(コード と呼びます)を書きます。ただし、コンピューターハードウェアがそれらのコードをすぐに実行できるわけではありません。ハードウェアが直接実行できるのは マシンコード あるいは 機械語 と呼ばれる一連のビットパターンだけです。すべてのプログラミング言語は、コンパイラ によってマシンコードに変換されるか(コンパイル型言語)、あるいは インタプリタ と呼ばれる別のマシンコードのプログラムによって解釈されて(インタプリタ型言語)、ハードウェアにそれらの命令を実行させるのです。
現在広く使用されているプログラミング言語には、Python、JavaScript、C、C++、Java、C#、Swift、PHPなどがあります。各プログラミング言語には、得意分野と苦手分野があります。よって、開発者が従事するプロジェクトや必要性に応じて、どのプログラミング言語を使うかを決めます。たとえば、大規模な業務用アプリケーションの開発にはJavaを使う、科学計算やデータ分析にはPythonを使う、といった具合です。
開発者は、創造力を発揮して、新しいプログラミング言語を発明してきました。初期のプログラミング言語は、コンピュータへの命令に似た 低水準言語 でした。現在では、命令の組み合わせを簡潔に表現できる 高水準 の言語へと発展してきています。言語によっては、人間の自然な思考方法を反映しやすくしながらも、厳密さを保っているものもあります。 約400のプログラミング言語が存在することが知られていますが、その多くは非常に限定されたアプリケーションや古い環境でのみ使われます。どのプログラミング言語も、現実の問題を解決するために開発されてきたのです。
プログラミング言語の特徴・構文・構造
どのプログラミング言語を選ぶかによって、ソフトウェアプロジェクトのパフォーマンスや拡張性、開発のしやすさは大きく変わってきます。この節では、プログラミング言語の重要な要素を説明します。
プログラミング言語の特徴
プログラミング言語一般の特徴として、次のような点が挙げられます。
- 並行処理
-
並行処理とは、複数のプロセッサで実行するか、一つのプロセッサでタスクを交互に切り替えることで、同時に複数の作業を行うことです。開発に用いるプログラミング言語がどの程度の並行処理をサポートしているかによって、特にリアルタイムでの処理や大量のデータ処理を求められるアプリケーションでは、パフォーマンスと拡張性が大きく違ってきます。並行処理をするために分割された作業は、プロセス、タスク、スレッド と呼ばれることがあります。
- メモリ管理
-
メモリ管理とは、プログラムでメモリを割り当てて解放する方法のことです。プログラミング言語やランタイム環境によっては、メモリ管理をプログラマが手動で行うこともあれば、自動的に処理されることもあります。プログラムがメモリを有効活用し、メモリ不足やその他の問題を引き起こさないようにするためには、適切なメモリ管理が極めて重要です。使われなくなったメモリを解放しなければ、メモリリーク が発生し、プログラムがクラッシュしたり明らかに動作が遅くなったりするに至るまで、メモリを使い尽くしてしまいます。
- 共有メモリ
-
共有メモリとは、複数のプロセスがメモリの同じ領域を読み書きできるようにする、プロセス間通信の仕組みの一種です。共有メモリは、ディスクドライブなどのハードウェアで一般的であり、プロセス間でデータを共有する効率的な方法でもあります。しかし、この仕組みでは、データが破損しないように、慎重に同期して管理しなければなりません。あるプロセスが、別のプロセスによって使用されているデータに予期せぬ変更を加えると、競合状態 と呼ばれるエラーが発生します。
- メッセージパッシング
-
メッセージパッシングとは、データをやり取りして状態を調整する、プロセス間通信の仕組みの一種です。並行プログラミングでプロセス間通信を実現するためによく使われます。ソケット、パイプ、メッセージキューなどの仕組みを通じて実装します。
- ガベージコレクション
-
ガベージコレクションとは、プロセスの実行中に使用されなくなったメモリを再利用できるように自動的にメモリを管理する技術のことです。メモリリークを防げるので、開発者は正常に動作するコードを楽に書けるようになります。他方で、パフォーマンス上のオーバーヘッドがあるとともに、プログラムの細かい動作をコントロールしにくくなるという欠点があります。
- データ型
-
データ型とは、プログラムで情報をどのように表現するかを定めた種類のことです。プログラミング言語であらかじめ決められていることもあれば、開発者が定義することもあります。整数、浮動小数点数(実数の近似値)、文字列、配列などのデータ型があります。
- 入出力(I/O)
-
入出力とは、プログラムがデータを読み書きする仕組みのことです。ユーザーのクリックやキーボード、ファイル、ネットワーク接続など、さまざまなところから入力がありますし、ディスプレイ、ファイル、ネットワーク接続など、さまざまなところへの出力があります。入出力を通じて、プログラムは外界と相互作用し、別のシステムと情報をやり取りします。
- エラー処理
-
エラー処理とは、プログラムの実行中に発生するエラーを検知して、それに応じた振る舞いをすることです。ゼロで割り算をするというエラーや、ファイルが見つからないというエラーなどがあります。適切なエラー処理を行うと、エラーが発生したとしてもプログラムが動作し続けるので、信頼性と堅牢性が向上します。
上記の概念は、プログラミング言語がどのように動くかを理解する基礎となり、効率的で保守しやすいコードを書く助けになります。
プログラミング言語の構文
プログラミング言語の 構文 とは、プログラムの文と式を書く規則のことです。構文が 明確 で 一貫 していれば、プログラマは効果的にコードを読み書きできます。以下の構成要素は、多くのプログラミング言語で採用されています。
- プロシージャと関数
-
プロシージャと関数は、同じコードを何度でも呼び出せるように、コードの再利用可能なまとまりを定義するために用います。
- 変数
-
変数はメモリの特定の部分を表していて、データを保持します。変数を使ってデータを操作し、プロシージャと関数にデータを渡せます。
- 演算子
-
演算子は、変数に値を代入したり算術演算を行ったりするための、キーワードや記号(
+
や-
など)です。 - 制御構造
-
プログラムコードは原則として記述された順序で実行されますが、制御構造 でそのコードの流れを変更できます。条件文 は、メモリの内容や、キーボードの状態、ネットワークからパケットが到着しているなど、さまざまな状態に基づいて、実行するコードを変更する制御構造です。条件文の特殊な形式である ループ文 は、一連のデータセットに同じ処理を行う場合に便利です。また、エラー発生時に特別なコードを呼び出す 例外 も、制御構造の一つです。 構文はプログラミング言語によって異なりますから、どのプログラミング言語を選ぶかによって、コードの読みやすさと保守のしやすさが変わってきます。
ライブラリ
よいプログラミング言語の条件は、既存のコードを再活用してプログラムを開発しやすいことです。多くのプログラミング言語では、プロシージャや関数をパーツ化して別のプログラムで再利用する仕組みが備わっています。
複数のプロシージャや関数を、機能や目的別に整理して1つのファイルにまとめたものを ライブラリ と呼びます。たくさんの使いやすいライブラリが利用可能であることも、よいプログラミング言語のとても重要な条件です。たとえば、PythonにはAI処理に適したライブラリがいくつも揃っていることから、AI関係のプログラム開発に適した言語であると広く認識されています。
プログラムが大規模で複雑になるに従って、既製のビルディングブロックとしてのライブラリの重要性が高まっています。特にオープンソースの世界では、他の人が作ったコードを取り込んで再利用することに抵抗がありませんから、プログラミング言語ごとにライブラリのエコシステムができあがっています。PHPの composer
、Pythonの pip
、Rubyの gems
などのパッケージマネージャで、ライブラリをインストールすることも簡単になっています。
コンパイル型言語 でもライブラリは重要です。コンバイルされた複数のバイナリファイルとコンパイル済みのライブラリを結合して、1つの実行可能ファイルを得る操作を リンク と言い、その操作を行うツールを リンカー と言います。アプリケーションの実行可能ファイルの中に必要なライブラリコードのみを取り込む 静的リンク という方法と、システムに1つだけインストールしたライブラリコードをそのライブラリを利用するすべてのアプリケーションで共有する 動的リンク という方法があります。現在、動的リンクが好ましいアプローチで、アプリケーションの実行可能ファイルサイズが小さくなる、実行時のメモリ使用量が少なくなるといった特徴があります。
ライブラリは複数のプログラムで使用できますから、ライブラリのバージョン間の違いがアプリケーション以上に問題になることがあります。ちょっと脱線しますが、ここでバージョン番号の見方を覚えておきましょう。セマンティックバージョニング(Semantic Versioning) と呼ばれる、ドットで区切った3つの数字でバージョンを表す方法が一般的に使われています。2.39.16
というバージョンなら、2がメジャーバージョンを示していて(数年に一度くらいしかメジャーバージョンは変わりません)、39がそのメジャーバージョン内でのマイナーバージョンを示していて(大きな機能変更のために数か月に一度くらいはマイナーバージョンが上がるでしょう)、16がリビジョンを示しています(一つのバグを修正するとリビジョンが上がります)。後のものほどバージョンやリビジョンの数字が大きくなります。
シンプルな例
ここまでの説明をイメージしやすくするために、プログラミング言語Pythonのシンプルなプログラム例を見てみましょう。
自然言語で表現するなら、このプログラムは、「ユーザーに数値の入力を求め、その数値が偶数か奇数を判定し、その判定結果を出力する」という動作をします。
以下のコードを simpleprogram.py
というファイル名で保存してください。
num = int(input("Enter a number: "))
if (num % 2) == 0:
print("The given number is EVEN.")
else:
print("The given number is ODD.")
このコードはたったの数行ですが、上で説明した特徴や構文をたくさん見いだせます。
-
1行目では、
num
という 変数 に、=
演算子 で 値 を代入しています。 -
代入された値は、
input()
関数 から返されたユーザーの 入力 です。さらに、int()
関数により、この入力値が整数の データ型 に変換されます。丸括弧内の関数に渡される式は、パラメータ や 引数 と呼ばれます。 -
ユーザーが(数値ではない)文字列を入力すると、
int()
関数の エラー処理 によってエラーを出力します。十進数の数値を入力すると、int()
関数が整数へと変換します。5.73
なら5
へと変換します。 -
2行目からは 制御構造 です。
if
とelse
というキーワードによる 条件文 です。入力値が偶数か奇数かという2つの可能性に応じた処理を行います。 -
剰余演算子(
%
)で入力値を2で割った余りを求め、それが0かどうか(2で割り切れるかどうか)を判定します(if
)。2で割り切れたら偶数です。==
は等価演算子です。1行目の代入演算子(=
)とは異なります。 -
そうでない場合(
else
)、つまり入力値を2で割った余りが0ではない場合、入力値は奇数です。 -
偶数の場合も奇数の場合も、
print()
関数がテキスト形式で結果を 出力 します。
以下のコマンドでこのプログラムを実行してみましょう。処理が行われます。
$ python simpleprogram.py Enter a number: 5 The given number is ODD.
この小さなコード例にもプログラミング言語のロジックが詰まっているのですから、数千ファイルからなる複雑なソフトウェアがどのようなことをできるかは推して知るべしです。Microsoft Windows、macOS、LinuxなどのOSは、コンピュータのあらゆるハードウェアを利用でき、ユーザーがさまざまなアプリケーションをインストールして仕事や遊びに使えるようにしているのです。
マシンコード、アセンブリ言語、アセンブラ
前述したように、ハードウェアが直接実行できるのはマシンコードと呼ばれる一連のビットパターンだけです。CPUは、メモリから1ワード(8〜64ビット)単位でビットパターンを読み出して、それが意味する命令を実行します。個々の命令はたとえば「メモリアドレスAの内容をメモリアドレスBにコピーしろ」、「メモリアドレスCの内容とメモリアドレスDの内容を掛け合わせろ」、「アドレスXにあるデバイスに到着したデータを読み出せ」といった極めて単純なものです。8ビットCPU時代にはマシンコードのすべてのパターンを覚えて、空でプログラムを直接書く猛者がいましたが、今は命令のパターンが桁違いに多くなったので、そんなことをできる人間はまず居ません。 マシンコードはビットパターンの並び、つまり0と1の羅列ですから、人間にとってはまったく直感的ではありません。プログラミングをより直感的にするために、命令に名前を付けて文字列で指定できるようにしたものが アセンブリ言語 です。アセンブリ言語では、マシンコードに1対1で対応する命令を1つずつ書いていきます。たとえばこんな具合です。
move [B], [A] メモリアドレスAの内容をメモリアドレスBにコピーしろ multi R1, [C], [D] メモリアドレスCの内容とメモリアドレスDの内容を掛け合わせろ input R1, [X] アドレスXにあるデバイスに到着したデータを読み出せ
アセンブリ言語の1つの命令が、マシンコードの1つの命令に対応するのがポイントで、ハードウェアが直接理解できる命令を正確に指示することができます。アセンブリ言語がマシンコードよりも優れている点は次のとおりです。
- 可読性と保守性
-
アセンブリ言語はマシンコードよりもはるかに読み書きしやすいです。人間が理解しやすく、デバッグが容易で、保守しやすいということです。
- アドレス計算の自動化
-
マシンコードのプログラミングでも変数や関数の概念を利用できますが、すべてを メモリアドレス の概念で表現しなくてはなりません。アセンブリ言語ではメモリアドレスにも名前を付けて、プログラムのロジックをわかりやすく表現することができます。
アセンブリ言語はハードウェアのすべての機能にアクセスできるので、以下のような場面でよく使われます。
- オペレーティングシステムのアーキテクチャ依存部
-
初期化やセキュリティ機能の利用のためにCPUアーキテクチャに固有の命令を使うには、アセンブリ言語を使うしかありません。
- 低水準のシステム装置の開発
-
デバイスドライバ、ファームウェア、BIOSなど、コンピュータのハードウェアに直接作用するシステム装置の開発に使います。特にハードウェアの性能を限界まで引き出す必要がある、高速デバイスのドライバやファームウェアでは、アセンブラによる細かなプログラミングが必要になることが少なくありません。
- マイクロコントローラのプログラミング
-
マイクロコントローラ(マイコン)と呼ばれる小型の低電力コンピュータが、玩具から産業用制御までの幅広い領域でよく使用されています。マイクロコントローラには、メモリ容量が数100バイトというものもあり、アセンブラでプログラムを作成するのが一般的です。
アセンブリ言語でのコードは、アセンブラ と呼ばれるアプリケーションで、マシンコードに変換してから実行されます。アセンブラは最古のプログラミングツールであり、マシンコードでのプログラミングでは考えられなかった数々の利点をもたらしました。混乱しがちですが、アセンブリ言語のことをアセンブラと呼ぶこともあります。
マシンコードやアセンブリ言語は、ハードウェアプロセッサごとにまったく異なります。ハードウェアを直接操作することから「低水準言語」と呼ばれます。しかし、いわゆる「計算」や「入出力」の概念は、どのプロセッサでも同じです。共通する概念を、より人間にわかりやすく表現できるようにすれば、プログラミングの効率は劇的に向上します。そこで登場してくるのが「高水準言語」です。
コンパイル型言語
コンパイル型言語 とは、ソースコードをマシンコードないし バイトコード と呼ばれる中間的な形態に変換してから実行するプログラミング言語です。バイトコードは、ハードウェアアーキテクチャの壁を越えてさまざまなコンピュータ上で実行されます。バイトコードは、ランタイム 仮想マシン によってそのコンピュータに適したマシンコードに変換されてから実行されるのです。この仕組みによって、プラットフォームに依存せず、仮想マシンを実行できるどのシステムでもプログラムを実行できます。
コンパイラが、高水準言語で書かれたソースコードを、マシンコードないしバイトコードへと変換します。直接マシンコードに変換されるコンパイル型言語には、C言語やC++などがあります。バイトコードに変換されるコンパイル型言語には、JavaやC#などがあります。
マシンコードとバイトコードのどちらを選択するかは、パフォーマンス、プラットフォームへの依存性、開発の容易さなど、プロジェクトの要件によって異なります。
インタプリタ型言語
インタプリタ型言語 とは、マシンコードにコンパイルするのではなく、インタプリタ によって実行されるプログラミング言語のことです。インタプリタがソースコードを読み取り、そこに書かれている文を実行します。インタプリタは、ソースコードを別のファイル形式に変換することなく、ソースコードをそのまま処理します。つまり、コンパイラのようにプログラム全体をまず変換するのではなく、インタプリタはコードの各行を読み取って1つずつ実行しますから、プログラマは実行結果をすぐに見ることができます。
インタプリタ型言語は、スクリプト(作業を自動化する短いプログラム)、コマンドライン、バッチ処理、ジョブ制御などでよく使われます。インタプリタ型言語で書かれたスクリプトは、コンパイルせずに簡単に修正して実行できるので、手っ取り早くプロトタイプを作って柔軟かつ迅速にイテレーション(反復)を繰り返すのに適しています。この便利さには、コンパイル型言語と比べて動作が遅い、スクリプトがあればソースコードを読めてしまうという代償が伴います。
インタプリタ型言語には、Python、Ruby、JavaScriptなどがあります。Pythonは、科学計算、データ分析、機械学習に広く用いられている言語です。Rubyは、ウェブ開発や自動化スクリプトの作成によく用いられます。JavaScriptは、動的でインタラクティブなウェブページを作るために使われる、ウェブブラウザに埋め込まれたクライアントサイドのスクリプト言語です。
データ指向言語
データ指向言語 とは、大量のデータを処理・操作することに最適化されたプログラミング言語のことです。大規模な構造的/非構造的データを効率的に処理でき、データベースを扱う作業に便利なツールやデータ構造が用意されていて、データの処理と分析に使えるアルゴリズムが備わっています。
データ指向言語は、データサイエンス、ビッグデータ分析、機械学習、データベースプログラミングなど、幅広い分野で使われています。データのクリーニングと変換、視覚化、統計モデリングなど、大量のデータを処理して分析する作業に適しています。
データ指向言語には、SQL(Structured Query Language)、R、MATLABなどがあります。SQLはリレーショナルデータベースを扱う際の標準言語で、産業界で広く用いられています。Rは統計計算とグラフ作成のための言語および環境で、データサイエンスと機械学習で広く用いられています。MATLABは数値計算の環境および言語で、信号処理、画像処理、金融工学で広く用いられています。
プログラミングパラダイム
プログラミング言語の特徴とは別に、プログラミングパラダイム によっても問題解決へのアプローチは変わってきます。プログラミングパラダイムとは、要件や条件に応じた、問題に取り組む際の基本戦略だと思ってください。
住宅の建設にたとえてみましょう。レンガを一つずつ積み上げて壁を作るか、それとも生コンクリートを流し込むかは、その家の特徴や場所(隣接状況)といった要件や状況に応じて決める基本戦略です。
プログラミングパラダイムを決めるのもこれと同じです。たとえば、一つのソフトウェアプロジェクトを小さい部分に分割するかどうか、分割するとしてどのように分割するかといった基本戦略です。プログラミング言語とプログラミングパラダイムとの間には相性があります。プログラミングパラダイムを決めると、自ずとプログラミング言語も決まってきます。
一般に、以下のようなプログラミングパラダイムがあります。
- オブジェクト指向プログラミング(OOP)
-
オブジェクト指向プログラミングは、オブジェクト という概念を基にしています。オブジェクトとは、クラス のインスタンスです(クラスが設計図だとしたらインスタンスは個別具体的な実体です)。クラスにデータ(プロパティとも呼ばれる)と振る舞い(メソッドとも呼ばれる)をカプセル化して閉じ込めるのです。たとえば、四角形クラスがあるとすると、プログラマはそのクラスをインスタンス化して四角形オブジェクトを作成し、(そのクラスの内部構造の詳細はわからなくとも)簡単に四角形を画面に表示できます。
オブジェクト指向プログラミングは、オブジェクトレベルでデータを操作します。そのおかげで、保守、再利用、拡張がしやすくなります。デスクトップソフトウェア、ゲーム、ウェブアプリケーションなどで広く用いられています。オブジェクト指向プログラミング言語には、Java、C#、Pythonなどがあります。
- 手続き型プログラミング
-
手続き型プログラミングは、さまざまな プロシージャ(コードのブロック)を組み合わせることで作業を遂行します。処理を追いやすいコードを書きやすいのですが、プロジェクトが複雑になるにつれて拡張や保守がしづらいコードになりがちです。手続き型プログラミング言語には、C、Pascal、Fortranなどがあります。
今日、ソフトウェア開発にはさまざまなアプローチが使われていて、それに応じた言語も開発されています。さらに、プログラマでなくてもドラッグアンドドロップで直感的にコードを書けるノーコードやローコードと呼ばれる方法もあれば、自然言語で命令をすれば人工知能がコードを生成してくれるオンラインサービスも存在します。
まとめますと、それぞれのプログラミングパラダイムには長所と短所があり、どのパラダイムを選択するかは、プロジェクトの必要性、開発者の経験と好み、プラットフォームと開発環境の制約に応じて決めます。どのようなタイプのパラダイムがあるのかを知っておくと、適切なパラダイムを選びやすくなりますし、よりよいコードを書く助けにもなります。
演習
-
関数の目的は何ですか?
-
マシンコードと比べてバイトコードにはどのような利点がありますか?
-
バイトコードと比べてマシンコードにはどのような利点がありますか?
発展演習
-
一つのプログラムを多数のプロセスに分割するデメリットは何ですか?
-
自分が書いているプログラムで必要な機能を備えたオープンソースのパッケージをいくつか見つけました。パッケージをどのような基準で選べばよいでしょうか?
-
オブジェクト指向プログラミングと手続き型プログラミング以外に、どのようなプログラミングパラダイムがあるでしょうか? また、そのプログラミングパラダイムに最も適しているプログラミング言語は何でしょうか?
まとめ
このレッスンでは、ソフトウェアとは何かということから、プログラミング言語を使ってどのようにソフトウェアを開発するかを説明しました。構文、ハードウェアリソースの管理、データ構造の扱いなど、諸々の点で異なるさまざまなプログラミング言語が存在します。
プログラミング言語は、ソースコードをどのようにマシンコードに変換するかという観点から、コンパイル型言語とインタプリタ型言語に分類できます。ソースコードは人間が読み書きしやすい形で、マシンコードはコンピュータが処理して実行できる形です。
ソフトウェアプロジェクトの要件や規模を考慮して、そのプロジェクトにふさわしい基本戦略を採用し、その戦略に適したプログラミング言語を選ぶという、プログラミングパラダイムの考え方もあります。
演習の解答
-
関数の目的は何ですか?
関数は、文字列を出力するといった一定の共通な処理をまとめるものです。関数を使うと、同じ処理をするコードを繰り返し書かなくても、いろいろなところからその関数を呼び出して何度でも実行できるので便利です。
-
マシンコードと比べてバイトコードにはどのような利点がありますか?
バイトコードは、仮想マシンがそのバイトコードをマシンコードに変換できさえすれば、いろいろなコンピュータで実行できます。たとえば、JavaScriptはいろいろなコンピュータのほとんどのブラウザで実行できます。
-
バイトコードと比べてマシンコードにはどのような利点がありますか?
マシンコードは最速で実行できます。バイトコードは実行時に仮想マシンがマシンコードに変換しなければならないので、その分だけ実行が遅くなります。
発展演習の解答
-
一つのプログラムを多数のプロセスに分割するデメリットは何でしょうか?
一つのプログラムを複数のプロセスに分割すると、相互に通信する必要が生じます。多くのデータを共有すると、データのやり取りや競合状態(他のプロセスが使用しているデータを変更してしまうこと)の防止にオーバーヘッドが発生します。プロセスの開始時と終了時にもオーバーヘッドが生じます。プロセスが多くなるほどプログラムの相互作用が複雑になり、エラーを見つけにくくなります。
関数型プログラミングというパラダイムでは、プログラムをたくさんのプロセスに分割するのですが、不変性(イミュータビリティ)によってこうしたデメリットに対応しています。データが不変であれば、競合状態が発生することはあり得ません。
-
自分が書いているプログラムで必要な機能を備えたオープンソースのパッケージをいくつか見つけました。パッケージをどのような基準で選べばよいでしょうか?
バグが多かったり安全でなかったりするパッケージもありますから、パッケージのバグレポートとセキュリティアドバイザリを確認します。最新の更新でセキュリティの脆弱性が入り込んでいるかもしれないので、最新のバージョンが必ずしもベストだとは限りません。
保守が積極的にされているかどうかを確認するために、パッケージの開発者フォーラムを追いかけてみてください。そのパッケージを利用して開発するプログラムは長い間使われるでしょうから、パッケージを安定的に使い続けられることが望まれます。
いくつかのパッケージを試してみて、動作の正確さとパフォーマンスを確認します。
ほとんどのパッケージは別のパッケージの関数を利用しているので(依存性)、利用するパッケージとそのパッケージが依存しているパッケージのどこかに脆弱性があると、プログラムに脆弱性があることになります。
-
オブジェクト指向プログラミングと手続き型プログラミング以外に、どのようなプログラミングパラダイムがあるでしょうか? また、そのプログラミングパラダイムに最も適しているプログラミング言語は何でしょうか?
オブジェクト指向プログラミングと手続き型プログラミング以外に、次のようなプログラミングパラダイムがあります。
関数型プログラミングは、ラムダ式やクロージャなど、数学的な関数の使用に力点を置いています。文を実行するというよりも、式を評価するという発想でコードを書きます。よって、関数が非常に重要な概念になり(プログラムは関数を操作するものだと捉えます)、不変性(変数を定義したら変更できないこと)を重視します。論理を追ってテストしやすいコードが書きやすくなり、並行処理・並列処理アプリケーションにも適しています。関数型プログラム言語には、Erlang、Haskell、Lisp、Schemeなどがあります。
命令型プログラミングは、プログラムの状態遷移の流れを制御するために必要な文に焦点を当てます。
宣言型プログラミングは、どうするべきかということを、その命令の背後にあるロジックとともに記述します。命令を実行する順番は固定されていません。ですので、論理さえ一貫していれば、命令と関数呼び出しその他の文の順番を並べ替えてコンパイラに最適化できます。
直感的プログラミングは、プログラムを動作させるために、自然言語その他の人間にとって自然な表現を用いるプログラミングパラダイムです。コンピュータ科学の訓練を受けていない人でもプログラミングができるようにしようという発想です。直感的プログラミング言語には、ScratchやAliceなどがあります。