見出し画像

『ソフトウェア作法』とプログラミングの心(マインド) (T1:Pt2:Ch01-1)

『ソフトウェア作法』は、原著が1976年(日本語訳1981年)と、現在2023年から50年ほど前に執筆され、プログラミングの参考書として今でもその名が挙げられることのある、コンピュータプログラミングの世界では古典と言ってよい著作です。

この書籍からソフトウェアデザインの考え方、よいプログラミングの取り組み方を紹介します。
「構造化設計」「構造化プログラミング」という、古くて永遠の、ソフトウェアのテストにも関係の深い話題です。



『ソフトウェア作法』と、その主題

道具として役に立つソフトウェアを作るよ!

『ソフトウェア作法』は原題を"Software Tools"といい、「我々が仕事をする上で、単体でも役に立ち、組み合わせて使えばもっと役に立つ、小さなプログラム」を“道具”と呼び、そうした「道具として使えるプログラム」の作り方を紹介しています。
UnixやLinuxをご存じの方なら、catとかwcとかtrとかtarとかsortとかgrepとか、マニアックな人ならedとかのコマンドを知っていると思いますが、そうしたコマンドを実際に作ってみようぜ、という本です(実際、本書所収のプログラムの相当数が、Unixコマンドにヒントを得ています)。
(また、個々のプログラムを走らせるプラットフォームについても、Unix的思想を追求しています)

ソフトウェアの“よい作り方”を教えるよ!

本書にはもうひとつ際立った側面があり、今回紹介するのはこちらです。
それは、「プログラムがどのような構造を持っているのが望ましいか、事前に検討(デザイン)することが大事だよ」という、「ソフトウェアデザインの考え方」「ソフトウェアづくりの進め方」を説いていることです。

(読んでいくと、先の「道具として使えるプログラム」も実はこの考え方の延長上にあることが判ってきます)


ソフトウェアづくりの進め方へのヒント

「(ソフトウェアデザインやプログラミングに関する)各種の思想を抽象的な原理で示す代わりに」「これらの原理から重要と思われる点を抜き出し、それをわれわれのプログラムの中で実践」([1] p.3)している著作から「抽象的な原理」を逆抽出するのは恐れ多い所業とは重々存じておりますが、実践例を踏まえた要点は抽出に値する、ということでどうかご寛恕のほどお願いいたします。
各節での箇条書きは、本書からの引用です。

①設計(デザイン)の初期は全体の構想に集中する

規模の大小を問わず、ソフトウェア/プログラムづくりの最初は、全体の設計に集中するべきだとしています。

  • ここでは一時的な処置として、棚上げにできる細部はなるべく棚上げにしてしまいたいわけである。 ([1] pp.12-13)

  • (システムとの文字の入出力を請け負う)getcやputcがそういう細部を隠してくれるおかげで、たいがいの人はそんなことは知らなくてもすむのである。 ([1] p.13)

  • (大きなプログラムの場合には、全体像を描いてから、それを)段々にくわしくして行く、というやり方は価値が大きい。このようにすれば、計算機に掛かる形のものを書くことなしに高いレベルで設計を改訂、改良して行き、しかも計算機で実行可能なものから遠く離れることなしに進んで行くことができる。 ([1] p.14)

  • (以上、太字は引用者)

【筆者補足】困ったことに、プログラミングをしていると細部の課題が気になることが頻繁に起こります。特に処理が難しい部分があったらそれを措いて別のことに集中するのは難しいものです。そこでつい気になったことに手を出して横道に逸れ、うまく行かずにはまってしまい、全体を見失う(時間も失う)……ということも頻繁に起こります。そうしたことへの戒めです。

(【さらに筆者補足】ただし、これは「デザインが固まるまでコードは一行たりとも書いてはいけない」ということではありません。思いついたアイデアで行けるかどうか、アルゴリズムが正しく働くかどうかなど、早めに解決しておきたいことについて、プログラムを走らせて確認してみるのは悪いことではありません(本書はそのようなことは明言していませんが、本書所収のプログラムのうちいくつかは幾度か試行を重ねたことは言っています))

②それはどんな「仕事」の集まりで実現されるか考える

全体像を描く中で、求められる機能/サービスを実現するには、どんな「仕事」があるか考えます。

  • この仕事は2段階にわけるのが一番よい。つまり まず行の1語目を見つけ出し、次にそれを「include」と比較する のである。 ([1] p.120)

基本的に、「仕事」として認識したものごとに、関数/サブルーチン等として作り込んでいくことになります。

③「階層」を意識する、「階層」を創り出す

全体が多くの細かい仕事でできている、というように考えるのでなく、全体(トップレベル)はいくつかの大きな仕事でできている、と考えるのが好ましいです。本書ではこれを「人間が頭の中で整理していける事項の個数の制約」からとしています(「マジックナンバー」などと言われますね)。

大きな仕事はそれよりも小さな仕事の集まり/組合せからなっています。複雑な仕事はそれよりも単純な仕事の組合せで実現されます。
小さな仕事に目を向けると、実はそれはさらに小さな仕事の集まり/組合せからなっています。

個々の「仕事」の中身を考える時に、全体を考えるのと同じように「この仕事はどんな「サブ仕事」の集まりで実現されるか」を考えます。こうして、全体から細部に向かって、ソフトウェア/プログラムの設計を階層的にしていきます。

  • この構成によれば、引数を一つずつ見て行く部分全体が一つのレベルにまとめられ、各ファイルについて行を見て行く仕事の詳細一切は、下のレベルに置かれることになる。([1] p.125, 太字は引用者)

④“プリミティブ”を考える

ソフトウェア/プログラムを構成する「仕事」の中で、最も基本となる関数サブルーチン(プリミティブ、本書中では「基本操作」)を考え、基本操作を用いて「仕事」をするように設計を組み立てていきます。

  • getcやputcのような関数を 基本操作(primitive) と呼ぶ。これが「外界」に対する窓口となる。 ([1] p.13)

  • われわれはこの問題を、基本操作 の考えに基づいて議論を進め、プログラムを書く、という方針によって回避することにする。すなわち、(略)概念的に単純で、それぞれ内容のはっきりした仕事をするいくつかの操作を考えるのである。 ([1] p.107)

  • オペレーティングシステム固有の性質を1箇所に閉じ込めるために 基本操作を定義し使用する というのは、プログラムの単位分解のきわめて重要な一形式である。 ([1] p.107)

  • (以上、太字は引用者)

⑤「独立した仕事」を見つける

「独立している」というのは、その「仕事」の中身を変更しようとした時、他の「仕事」や呼び出し元を合わせて変更する度合いが小さいということです(ゼロなら理想的)。

「独立」しているかどうか判断する手がかりとしては:

  • 他の箇所との結びつきが弱いと考えられる

  • 「その仕事だけが知っていればいい」ことがある

  • 頻繁に行なわれる「仕事」である

「他の仕事との結びつきが弱い」「その仕事だけが知っていればいい」ことがある なら、それがたとえ一回しか行なわれない仕事でも、独立した仕事にする値打ちがあります。

  • わずか5行の、しかも1回しか呼ばれない関数をわざわざ作るのはばかばかしいと思われるかも知れないが、settabの目的は、データ構造を隠して、それを知らないでよいルーチンには知らせないようにする、というところにあるのだ。 ([1] p.35)

頻繁に呼び出される仕事 は、それが“つまらない仕事”だとしても独立した仕事にする値打ちがあります。

  • (サブルーチンcantは)つまらない仕事だけれども、非常にしばしば必要となるので、独立のサブルーチンを用意しておくだけのねうちがある。 ([1] p.116)

⑥段階的に、「実際に動かして働く」ものに近づける

これらを、全体(トップレベル)から始めて段階的に進めていき、実際のプログラムに近いレベルまで詳細化していくことで、「よい構造を持ったプログラム」が考えやすくなります。


構造化されたソフトウェア/プログラム

基本的な思想

本書は、ソフトウェア/プログラムの設計・実装のこのようなアプローチを「構造化設計」と呼び、その基本的な思想を次のように述べています。

構造設計法(structured design)とは、システムないしプログラム全体の設計を、各部分がうまくかみ合い、しかも相互の結合が個々に作り換えができるに十分なほど少なくなるように統御していくことをいう。

([1] p.3)

大きいプログラムの場合にはプログラムを細分化して、各部がはっきりした界面のみを通じて情報のやり取りをするように仕組むことは、きわめて重要である。プログラムの一つの部分がほかの部分の働きについて知っていることが少なければ少ないほど、それらの部分を変更することは容易になる。

([1] p.36)

そのための、われわれが知る限りでのもっともよい方法は、プログラムの各部分をできるだけよく切り離し、変更をしてもほかの部分には影響が及ばないようにする、というものである。おもてに出すとプログラムの一般性を弱め、プログラムの動作様式に限定を加えてしまうような細部は、なるべく個々のプログラム単位に押し込めてしまうようにする。

([1] p.36)

ほかの話題は今回割愛しています

ここに抽出した要点以外にも、本書には実践例を踏まえて示唆に満ちた記述に溢れていますが、すべて挙げると結局「『ソフトウェア作法』を読みなさい」になってしまうので今回は割愛します。

“構造”はソフトウェアのさまざまな階層(レベル)で考えることができますし、考えるべきものです。本書でもいくつかのレベルに言及しており、非常に興味深いのですが、この話題も別の機会に別の記事で取り上げられたらと思います。

テストや品質の観点から

「構造化設計」のアプローチは、テストやソフトウェア品質確保の立場から見ても重要で意義深いものであることは言うまでもないでしょう。

ソフトウェアは、いくつかの「(大きめの)仕事」が集まって動いている。その「(大きめの)仕事」は、それぞれが「(いくらか小さい)仕事」が集まって成り立っている。その「(いくらか小さい)仕事」は、さらに「(もっと小さい)仕事」の集まりでできている。

あるレベルの「仕事」が果たされるためには、それより下位のレベルの「仕事」が適切な働きをしていることを確認できている必要があります。
下位レベルの「仕事」についても同様に、さらに下位の「仕事」の働きを確認する必要があります。
複数の「仕事」が組み合わさってしかるべく(上位の「仕事」のために)働くことも確認する必要があります。

ISTQBでいうテストレベル、コンポーネントテスト(単体テスト)や統合テスト(結合テスト)はまさにこういうことをテストするものですし、重要さも明らかでしょう。
それぞれの「仕事」が「互いによく切り離され」ていて、「各部がはっきりした界面のみを通じてやり取りをする」ように作られていれば、単体テストや統合テストもやりやすいわけです。
(ISTQBのトレーニング(研修)などではいつもテストレベルの説明には言葉を尽くすのですが、これからは「この記事を読んで」と言えそうです^^)

(本書中の、ソフトウェアテストに関する言及については姉妹編「『ソフトウェア作法』にみるテストの心(マインド)」(T1:Pt2:Ch01-2)をご覧ください)


むすび

「構造化プログラミング」「構造化設計」という用語については、拙稿「構造化プログラミングとゾルトラーク」で軽く触れていますが(“狭義の構造化プログラミング”についてのみ言及)、
『ソフトウェア作法』が執筆された時代から50年ほど経った2023年、コンピューターやプログラミングの技術は“進歩”し、今では滅多に聞かれなくなりました。

それは、「よい構造を持つ」という考え方や取り組み方が現在のテクノロジーの根底に根づいたからで(特にプログラミング言語のサポートは目覚ましいものがあります)、表立って言われなくなっただけだと思います。

本書が書かれた時代から現在まで、ソフトウェアの規模と複雑さは増大する一方です。ソフトウェア/プログラムにいかに「よい構造」を創り、それを維持するかは、今後も続く課題と言ってよいでしょう。
基本を押さえておく、基本に立ち戻るという意味で、一読に値する書籍だと思います。

最後に「エピローグ」から一節を引いておきます。

複雑さの管理はプログラミングの真髄である。(略)複雑さの飼い慣らしかたは、本書の一つの中心主題なのであった。

([1] p.488, 太字原文ママ)

文献・書誌情報

  • [1] Brian W.カーニハン, P.J.Plauger (木村泉・訳) 『ソフトウェア作法』 (原著1976, 日本語訳1981) 共立出版

    • 原著 (日本語訳の扉記載の情報に基づく)

    • Software Tools

    • Brian W. Kernighan, P. J. Plauger

    • 1976初版 (Addison-Wesley)


(2023-12-28 R001)

この記事が気に入ったらサポートをしてみませんか?