My Favorite Life

Go there and write simply with golang. Such a person I want to be.

手を動かしてGo言語で実装しながら『コンピュータシステムの理論と実装 ―モダンなコンピュータの作り方』を読んだ(後半)

前回の記事

abemotion.hatenablog.com

6章 アセンブラ

本章で説明する内容は、アセンブリ言語で書かれたプログラムをバイナリで書かれたプログラムへ変換するために、アセンブラがどのようなことを行っているか、ということである。

実装したプログラム

Go言語を用い、記号表記で書かれている低水準言語の xxx.asm ファイルを、16ビットのバイナリコードで表現される xxx.hack ファイルへと変換するアセンブラの実装を行った。
アセンブラはユーザーの定義したシンボルを扱う事ができるようにする必要があるので、シンボルテーブルを使って、シンボルから物理メモリアドレスへと変換する考え方が学びとなった。

7章 バーチャルマシン#1:スタック操作

本章はコンパイラの構築へ向けた初めの一歩である。このコンパイラは、オブジェクトベースの一般的な高水準言語をコンパイルする。コンパイラを作るという作業は相当に困難であるため、我々はその作業を2段階に分けて取り組むことにする。このふたつの段階にはそれぞれ2章分のページが割かれ、合計で4章に渡って説明を行う。高水準プログラムは初めに中間コードへに変換され(10〜11章)、その中間コードは機械語へと変換される。(7〜8章)
この2段階による変換処理のモデルは1970年代までさかのぼる古くからあるアイデアに基づいている。1990年代後半には、JavaやC#などのモダンな言語においてもそのアイデアが取り入れられ、再び脚光を浴びることとなった。
中間コードは実際のプラットフォーム上で実行される代わりに、VM上で実行されるように設計されている。これが基本となるアイデアである。VMは抽象化されたコンピュータであり、実際には存在しない。しかし、他のコンピュータ上で再現することができる。このアイデアの優れている点はたくさんあるが、そのうちのひとつは「コードの移植性」についててである。VMを複数のプラットフォームを対象に実装することは比較的容易であろうから、元となるソースコードを修正することなく、VM用のソフトウェアを他のプロセッサとOS上でも実行させることができる。
高水準言語で書かれたプログラムを特定のコンピュータ上で実行するためには、プログラムをそのコンピュータの機械語に変換しなければならない。この変換作業は「コンパイル」という名前で知られている。いくぶん複雑な工程となる。コンパイラを実装するには、どのような「高水準言語」と「機械語」を対象とするのであれ、そのふたつの組み合わせに依存したプログラムを書かなければならない。そのため、対象とするコンピュータと言語の組み合わせに応じて、別のコンパイラが必要になる。
この「高水準言語」と「機械語」による依存性の分離は、コンパイルという作業全体をふたつのステージに分けることで行うことができる。最初のステージにおいて、高水準言語がパースされ、そのコマンドが中間コードへと変換される。そして、次のステージにおいて、その中間コードが対象とするハードウェアの機械語へと変換される。このふたつのステージへと分離することによってもたらされる恩恵は、ソフトウェア開発の観点から見ると、とても魅力的である。なぜなら、最初のステージは高水準言語の仕様だけに依存し、2番目のステージは対象とする機械語の仕様だけに依存するからである。

実装したプログラム

  • VM変換器(スタック算術/メモリアクセスに対応)

Go言語を用い、VMの中間コードで書かれている xxx.vm ファイルを、アセンブリ言語である xxx.asm ファイルへと変換するVM変換器の実装を行った。
ここからスタックというデータ構造が登場し、この章以降、全てのデータや計算結果のやりとりがスタックを通じて行われる。

8章 バーチャルマシン#2:プログラム制御

コンピュータサイエンスにおいて"処理コンテスト"のようなものがあるとしたら、スタック処理は優秀部門でノミネートされるだろう。前章では、算術演算とブール演算が基本的なスタック操作によって計算できることを示した。本章では、この驚くべき単純なデータ構造が、驚くべき複雑な仕事をこなせることを示す。複雑な仕事とは、ネスト化されたサブルーチン呼び出しや引数の受け渡し、再帰処理やメモリ割当などである。ほとんどのプログラマーは、これらの機能をコンパイラが何らかの方法で実現しているとは知りつつ、当たり前のことだと思っている。我々は今、このブラックボックスを開く場所に来た。このプログラミングにおける基本的なメカニズムは、スタックベースのVMによって、実際どのように実装されているのか?
本章は、この問題について考える。

実装したプログラム

  • VM変換器(プログラムフロー/サブルーチン呼び出しまで対応)

Go言語を用い、前章で構築したVM変換器の拡張を行った。
if 文や while 文がどのようにアセンブリ言語で記述され、関数呼び出し時に、呼び出し側関数に渡された引数、ローカル変数の保存、制御がどのように呼び出された関数に移され、返り値がどのようにかえってくるか、それが全てスタック上でどうやって処理されるか、VM変換器を構築することで理解することができた。

9章 高水準言語

これまで本書で提示してきたハードウェアとソフトウェアはすべて低水準(低レイヤ)に関するものであった。低水準とは、つまり、人が直接読み書きすることを想定していない、ということである。本章では、Jackと呼ばれる高水準言語について説明を行う。Jackは、人であるプログラマーが高水準なプログラムを書くために設計されている。
Jackは、シンプルなオブジェクトベースの言語である。基本的な性質を備えており、モダンな言語であるJavaやC#と同じような見た目であるが、より単純化された言語であり、「継承(inheritance)」はサポートしていない。

本書で提供されているJackというプログラミング言語の仕様が説明されている章で、10章と11章でJackプログラムをVMコードへ変換するコンパイラを書く際に主に参照した。

10章 コンパイラ#1:構文解析

本章では、Jack言語のコンパイラを作る。コンパイラは、一言で言えば、変換を行うプログラムである。ソース言語で書かれたプログラムを目的の言語で書かれたプログラムへ変換する。この変換のプロセスをコンパイラと呼ぶ。この変換プロセスは概念的にふたつの作業に基づいている。
ひとつ目の作業は、ソースプログラムの構文を理解し、そこからプログラムの意味を明らかにすることである。たとえば、コードを構文解析することによって、そのプログラムは配列を宣言していることが明らかになる、ということがそれに該当する。そのパースした情報を用いることで、目的とする言語の構文からプログラムのロジックを再構成することができる。最初の作業は一般的に構文解析と呼ばれ、本章のテーマである。ふたつ目の作業であるコード生成は次の11章で扱う。
コンパイラをゼロから書くには、コンピュータサイエンスにおける重要なトピックを学ぶ必要がある。学ぶべきことは、言語変換と構文解析、木やハッシュテーブルなどのデータ構造の使い方、再帰的なコンパイルアルゴリズムなどである。そのため、コンパイラを作る作業はたいへんな仕事でもある。
なぜ我々は骨を折ってまでしてコンパイラを作ろうとしているのか? ひとつ目の理由は、コンパイラの内側を知ることによって、より優れたプログラマーになれるからである。ふたつ目の理由は、プログラミング言語を記述するために使われるルールや文法は、他の分野においても応用できるからである。

実装したプログラム

一般的なコンパイラは主にふたつのモジュールからなる。
それは構文解析とコード生成を行うモジュールである。構文解析を行う作業は、通常さらにふたつのモジュールにわけられる。それはトークナイザとパーサである。トークナイザは、ソースコードに対して意味を持つコードの最小単位である「トークン」に変換する。パーサは、一連のトークンを言語の構文ルールに適合させ、その構文構造を明らかにする。
本章では、コンパイラ構文解析器だけに焦点を当てた。
構文解析器が行う仕事は「プログラムの構造を理解する」ということである。
Go言語を用い、入力プログラムの構文構造を反映したXMLを出力するコード生成機能を備えない構文解析器を実装した。

11章 コンパイラ#2:コード生成

多くのプログラマーにとって、コンパイラはあたりまえの存在である。しかし、少し時間をとってコンパイラについて考えてみれば、高水準言語をバイナリコードへと変換する能力は魔法のように感じられるのではないだろうか。本章では、この変換作業を理解するために、実際にコンパイラを開発する。
10章では、Jackプログラムを理解できる構文解析器を構築した。本章で、この構文解析器を完全版のコンパイラへと拡張する。完全版のコンパイラは、理解された高水準言語を、同等の内容である一連のVM命令へと変換する。このアプローチは「分析と合成(analysis-synthesis)」のパラダイムに従ったものである。ほとんどすべてのコンパイラも、これに従う。

実装したプログラム

コンパイラ全体の作業はバイナリコードまでの変換を含む。しかし、VMコードから機械語へと変換する部分はこれまでの章で構築したので、本章で作成するコンパイラは高水準言語からVMコードを生成することだけを目標とすればよい。
前章のコンパイラを拡張して実装を行ったが、ただXMLを出力するのとは大違いで大変であった。
VMコードを生成するためJack言語の文法を更に深く理解して構文解析を行い、全ての変数・配列・オブジェクトをシンボルテーブルを用いて処理し、フロー制御、サブルーチン呼び出しがメモリ・スタック上でどのように表現されるか把握しながら、VMコードの仕様も理解し変換するコンパイラを実装した。

12章 オペレーティングシステム

これまでの章は全て実装を行ってきたが、本章は迷ったが実装を割愛した。
理由は本書で提供されているJack言語を用いて OSを構築する必要があり、Go言語を用いることができない。
また結果としてできあがるJackOSは商用のOSと似た特徴を多く持つが、プロセス操作やディスク管理、通信などといった商用OSが持つ機能を欠いている。
このプロセス操作や通信という部分をもっと深く学びたい、かつ JackOS の各クラスで提供する機能はどれもシンプルな物であり、これまでの章で遭遇してきた高い山の様には感じないので、この本にはいったん区切りをつける事とした。

まとめ

本書で最初に提供されるNAND素子から、Not/Andという単純な回路をHDL言語を用いて作り、マルチプレクサ、最初の山であるALU(算術論理演算器)を構築し、レジスタ、メモリ、CPUとハードウェア部分を実装してきた。
ソフトウェア部分では、アセンブリ言語機械語へ変換するアセンブラコンパイラを2段階に分けて(高水準言語→VMコード/VMコード→アセンブリ言語)、Go言語を用い、基本的には全てロジックを考え実装を行った。
後半に進むにつれて必要とされるコード/ロジックを想像するに、最初はどれも途方にくれたが、時間をかけて作り上げることができた。
1年以上この本に取り組み低レイヤについて理解を深めることができたが、学びたい事はまだまだあるため、さらに学んでいきたい。

本書は"発見の旅"である。
本書によって、読書は次の3つのことを学ぶことになる。それは「コンピュータの動く仕組み」「複雑な問題を扱いやすいモジュールに分割する方法」そして「ハードウェアとソフトウェアからなる巨大なシステムを開発する方法」である。
本書では、実践的な作業を通じて、完全なコンピュータシステムを作り上げていく。この作業を通じてあなたが学ぶであろう教訓は、コンピュータそれ自体よりも価値があり普遍的なものである。心理学者であるカール・ロジャーズは言う「人に重要な影響を与える唯一の学びは、自己発見・自己本位による学び、つまり、経験によって理解された真実のみである」と。

コンピュータシステムの理論と実装 ―モダンなコンピュータの作り方

実際のコード

github.com

手を動かして実装しながら『コンピュータシステムの理論と実装 ―モダンなコンピュータの作り方』を読んだ(前半)

コンピュータシステムの理論と実装 ―モダンなコンピュータの作り方

最初は効率優先で内容だけ理解しようと3章まで読み進めたが、 理解が前提となっている各章末の実装部分を飛ばしている事で、徐々にしっくり来ない違和感が増えてきてしまった。

それに、まえがきにもこう書いてある。

コンピュータはどのように動いているのか?
それを理解するための最善の方法は、コンピュータをゼロから作り上げることである。筆者らはそのように信じて疑わない。
その考えに則り、考案したプランは次のようになる。まず、単純ではあるが十分にパワフルなコンピュータシステムを明確に規程するところから始める。
そして、そのプラットフォームとなるハードウェアと階層構造からなるソフトウェアをゼロから作り上げていくのである。
ここで「ゼロから作る」という言葉を用いたが、これは、基本要素として使えるパーツは論理ゲートだけであるということを意味する。
つまり、論理ゲートだけを用いてコンピュータの構築を行うという計画である。

なので、そもそも手を動かして「作る」という事を行わないと、本の意図ともずれてしまう。 そこで私は、主に欧米の大学でコンピュータサイエンスの教科書として使用されてきたこの本にしっかりと向き合おうと決めた。 ここからはコロナ禍で取り組むにあたって読んだ本を「準備編」として紹介し、 それから各章の内容を記していく。

準備編

コロナの影響で在宅・リモートワークが当たり前となり、急に人間の自律性がより強く求められる世の中になった。 出社という強制的なイベントが減り、往復の通勤時間がなくなり自由な時間が増えた。 活かせるかどうかはその人次第。という事で行動様式を見直す/学ぶ良い機会と捉え、以下の書籍を読んだ。

すぐやる! 「行動力」を高める“科学的な”方法

作業療法士の方が書かれた本で、脳機能の観点から行動を変える方法が書いてある。 →この本を読み、家でのタスク等すぐに取りかかる事が圧倒的に増えたので効果に驚いている。

習慣が10割

習慣のメリットや習慣でどう人生が変わるかというエピソードが書かれており、習慣形成のコツが得られる。

小さな習慣

個人的にはこれが1番オススメで、

  • モチベーションに頼るのはどうして上手くいかないのか
  • 大きな目標を前にすると、なぜ意志の力が消耗するのか

といった事が書かれており、共感する点が多かった。

これらの本を読み、

  • 毎日少しずつでもいいから進める
  • 「理解」を重視し時間をかける
  • 実装部分は基本自分で考えて解く
    (本を読み理解している文法では解けない/時間がかかる場合のみ調べる事にした)

というルールを設定し、1章から再スタートした。

1章 ブール論理

あまりに単純なものから、人間が手に負えないほど複雑なものが作られる。
- アメリカの詩人 ジョン・アッシュベリー

この本には様々なシミュレーターが提供されているので、 実際に「作る」と言っても、はんだごてを使ったり部品を用意する必要はない。 コンピュータ上でハードウェア記述言語(HDL)を用いて、回路のアーキテクチャを設計し、最適化について考えることができる。

出発点はNandゲートであり、このNandゲートから他のすべてのゲートと回路が作られる。 このゲートは基本要素として使うため、実装する必要はなかった。

実装した論理ゲート

  • Not
  • And
  • Or
  • Xor
  • マルチプレクサ(Mux)
  • デマルチプレクサ(DMux)
  • 多ビットNot/And/Orゲート
  • 多ビットマルチプレクサ

ここらへんはまだ簡単というか、ロジックも単純であり、 普段プログミングに出てくるいわゆる Not(!)やAnd(&&)を実装していて楽しかった。

効率の点で言えば、一般的な指標は「do more with less」
つまり「ゲートの数をできるかぎり減らせ」ということになる。

ゲートの仕様(インターフェース)が与えられたとき、
すでに実装済みの他のゲートを用いて対象のゲートを実装する効率的な方法を探す、ということである。

2章 ブール算術

本章では、数を表現し算術演算を行うための論理ゲートを作成する。
コンピュータで行われる算術演算と論理演算はすべて、このALU回路によって行われる。
そのため、ALUの機能を理解することは、CPU、さらにはコンピュータ全値の仕組みを理する上で重要なステップとなる。

2真数の加算は単純な演算であるが、奥が深い。
驚くべきことに、デジタルコンピュータによって行われる命令の多くが「2進数の加算」へと還元することができる。
そのため、コンピュータの多種多様な命令を実装するにあたって、2進数の加算を理解することが重要である。

実装した回路

  • Inc16(加算器):与えられた数字に1を加算できる回路
  • Add16(加算器):2つの16ビットの和を求める
  • HalfAdder(半加算器):ふたつのビットの和を求める
  • FullAdder(全加算器):3つのビットの和を求める
  • ALU(算術論理演算器):Hackと呼ばれる特定のコンピュータプラットフォームで使われる専用の回路

ほとんどが入力の数も限られており実装も単純だったが、 ALUは入力も8つ、出力も3つあり、仕様を見るだけでも組み合わせが多く、大変だった。 コードは整理すればもっと短く書けるとも感じるが、1つずつコツコツ組み合わせていった。

2の補数
2進コードにおいて符号付き整数を表現するため、これまでいくつかのコード体系が考案されてきた。
今日ほとんどすべてのコンピュータで用いられる方式は、2の補数と呼ばれる方式である。

3章 順序回路

1章と2章で構築した論理演算や算術演算の回路はすべて、組み合わせ回路と呼ばれる。
組み合わせ回路は、入力値の組み合わせだけによって、関数の値が決定する。
このどちらかと言えば単純な回路は重要な処理をたくさん行うことができるが、
状態を保つことはできない。
コンピュータは値を計算するだけでなく、その値を保存し呼び出すことができなければならない。
そのため、時間が経過してもデータを記憶することのできる記憶素子を備える必要がある。
この記憶素子は順序回路から構築することができる。

Go言語に取り組んでから、知りたいという好奇心が強くなっていると感じている。
やはりドキュメントを読んでも挙動が分からない時など、ライブラリの中身などを型に制御されながら追っていくので理解が深まる経験を多くする。
メモリは、机の上に例えられたり一時的に記憶できる装置と言われる事もあるが、(最初のとっかかりとしては良)
そういった表面上で捉えるための説明ではなく、一体どう構成されていてどう動いているのかちゃんと理解したいと感じるようになってきた。

この章はそんな欲求に応えるのにぴったりで、
クロック→フリップフロップレジスタ→メモリと全ての説明が連結していく。 より下位レベルの抽象化から、より複雑なものへとボトムアップ的な視点で捉える本書のアプローチをまさしく感じる章になっている。

実装した回路

4章 機械語

何事もできるかぎりシンプルにすべきだ。だが、シンプルにしすぎてはいけない。
- アルベルト・アインシュタイン
コンピュータを構造的な視点から説明するには、そのハードウェアプラットフォームを定時し、
それが下位レベルの回路からどのように構築されているかを説明すればよい。
また、コンピュータを抽象的な視点から説明するには、その機械語の仕様を示し、
その機械語によって何ができるかを明らかにすればよい。
実際のところ、新しいコンピュータシステムに慣れ親しむためには、開会後で書かれた低水準言語のプログラムを最初にいくつか見るのが手っ取り早い。
これは、コンピュータに何か有用なことを実行させる方法を理解するだけではなく、ハードウェアなぜそのように設計されているかを理解するためにも役立つ。
その点を考慮して、本章では機械語による低水準のプログラミングに焦点を当てる。
Hack機械語の仕様
概要
Hackコンピュータはノイマン型のプラットフォームである。
それは16ビットのマシンであり、CPU、メモリモジュール、メモリマップドI/Oデバイスを備える。
メモリモジュールには命令用とデータ用のメモリが離れた場所に存在する。
メモリマップドI/Oデバイスじゃスクリーン用とキーボード用のふたつがある。

実装したプログラム

  • 乗算プログラム
  • 入出力操作プログラム

アセンブリプログラムを書き、本書で提供されているアセンブラ機械語に変換し、CPUエミュレータを用いて、実行/テストを行う。

5章 コンピュータアーキテクチャ

本章は"ハードウェアの旅路"における頂きである。
ついに、1~3章までに作成した回路を使って、汎用コンピュータを作る準備が整った。
この汎用コンピュータは、メモリに格納された機械語プログラムを実行することができる。
我々が作ろうとしているコンピュータ-このコンピュータはHackと呼ばれる-は、ふたつの重要な性質を持つ。
まずひとつに、Hackはシンプルなマシンであると言える。
これまでに構築した回路と本書が提供するハードウェアシミュレータを用いれば、ものの数時間で作ることができる。
また、その一方で、Hackは十分にパワフルなマシンであり、デジタルコンピュータの主要な動作原理とハードウェア要素を兼ね備えている。
そのため、Hackを作ることで、「現代のコンピュータがどのように動作しているのか」ということについて、
ハードウェアとソフトウェアの低レイヤのレベルで理解することができるだろう。
ノイマン型コンピュータは実用的なアーキテクチャである。
今日のコンピュータプラットフォームはほとんどすべて、このノイマン型コンピュータと概念上の枠組みは同じである。
ノイマン型アーキテクチャは中央演算装置を中心として、メモリデバイスを操作し、入力デバイスからデータを受け取り、
出力デバイスへデータを送信する。
このアーキテクチャの心臓部は「プログラム内臓」という方式にある。

構築した内容

  • Memory
  • CPU
  • Computer

この本は単なる架空のコンピュータを作らされるわけではなく、現実に即しているため実用的な点が良い。
またプリミティブな要素として基本部分はブラックボックスとして提供されるが、 それを除けば、これまでの章が全て土台となり積み重なって曖昧な所がなく構築できるため、理解度も深い。

6章からはどれかプログラミング言語を選択して実装していく部分もあるため、Go言語を用い取り組んでいきたい。 後半に続く。

実際のコード

github.com

http Middleware in golang (Handler/HandlerFunc/Handle/HandleFunc)

業務では gRPC を使って開発しているのもあり、net/http パッケージを使用することは少ない。

時々、別プロジェクトで必要になったり、記事で見かける度に理解し直す部分を感じるので、自分用にメモ。

全ては Handler である

まずは結論とコードから。

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}
type HandlerFunc func(ResponseWriter, *Request)

func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request)

HandlerFunc は ServeHTTP を実装しているので、Handler である。

func Handle(pattern string, handler Handler) {
    DefaultServeMux.Handle(pattern, handler)
}

DefaultServeMux は Serve によって使用される、デフォルトの ServeMux である。

func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
    if r.RequestURI == "*" {
        if r.ProtoAtLeast(1, 1) {
            w.Header().Set("Connection", "close")
        }
        w.WriteHeader(StatusBadRequest)
        return
    }
    h, _ := mux.Handler(r)
    h.ServeHTTP(w, r)
}

ServeMux も ServeHTTP を実装しているので、Handler である。

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    DefaultServeMux.HandleFunc(pattern, handler)
}
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    if handler == nil {
        panic("http: nil handler")
    }
    mux.Handle(pattern, HandlerFunc(handler))
}

第二引数の func(ResponseWriter, *Request) は内部で HandlerFunc に変換される。
(HandlerFunc は Handler)

func ListenAndServe(addr string, handler Handler) error {
    server := &Server{Addr: addr, Handler: handler}
    return server.ListenAndServe()
}

ListenAndServe(":8080", nil) のような形で handler = nil で call されると、DefaultServeMux が使用される。

この前提を持って、Middleware を見ていく。

Middleware

通常

http.Handle("/test", testHandler)

Middleware 使用

http.Handle("/test", Middleware()(testHandler))

func Middleware() func(http.Handler) http.Handler {
        return func(h http.Handler) http.Handler {
                return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
                        log.Println("before")
                        defer log.Println("after")

                        h.ServeHTTP(w, r)
                })
        }
}
  • Middleware() は func(http.Handler) http.Handler を返す
    • つまり return func(h http.Handler) http.Handler {} の部分
  • Middleware()(handler) とは返ってきた func(http.Handler) http.Handler を実行する
    • func(testHandler) http.Handler となっている
  • testHandler の前後で処理を行い、testHandler.ServeHTTP(w, r) を実行し、 無名関数を http.HandlerFunc() へ変換し、新しいHandler をreturn する。

という流れ。
このつくりだと、1つの Middleware しか受け取れず使い勝手が悪いが、
func (h http.Handler, middlewares ...func(http.Handler) http.Handler)
このような形で複数受け取れる関数を用意し、range などで回すと好きなだけ実行することが可能である。
詳しくは参考リンクを参照されたい。

参考

Writing middleware in #golang and how Go makes it so much fun. | by Mat Ryer | Medium

http - The Go Programming Language

【本メモ】『初めてのGraphQL ―Webサービスを作って学ぶ新世代API』

『初めてのGraphQL ―Webサービスを作って学ぶ新世代API』を読んだので、本メモを公開。

初めてのGraphQL ―Webサービスを作って学ぶ新世代API

読んでみたが、やはり動かしてみないと全体像をイメージして理解できるようにはならないし、 Tips集を読んでいるような印象を受けた。 実装して手を動かしながら、時おり迷った際などに参照しつつ進めるのが良いかもしれない。 ただ書く言語ごとによってまた事情が異なるはずだし、テストなどについても本書には記載があまりないので、 新技術かつ事例もまだ少なく、試行錯誤しながらになると思われる。

type Query {
......
      allUsers(first: Int=50 start: Int=0): [User!]!
}

上の例では first と start のオプショナルな引数を追加しています。また、クライ アントがクエリにこれらの引数を指定しなかった場合はデフォルトの値が使用されるよ うになっています。

ここまでRESTの課題に関して議論してきましたが、多くの組織ではGraphQLと REST を併用していることについても言及しましょう。GraphQL のエンドポイントを 作成し、GraphQL サーバーから REST のエンドポイントへリクエストするというやり 方は、GraphQL の使い方として何ひとつ間違っていません。皆さんの組織に漸進的に GraphQL を導入するための最適な方法です。

可能であれば、GraphQL のサービスは無向グラフにしておくことが望ましいです。

「3章 GraphQLの問い合わせ言語」でGraphQLのイントロスペクション機能について 紹介しました。GraphQL は利用できるクエリに関する情報を提供できます。GraphQL のスキーマを作成するとき、それぞれのフィールドにスキーマの型やフィールドに対す る説明を付加できます。説明を付加することで開発チームメンバーや自分自身、あるい は API のユーザーが API を理解する助けになります。


モックはそれぞれのスキーマ型に対するデフォルト値を出力します。フィールドが文 字列に解決されることが想定される場所では常にデータとして"Hello World"が与えら れます。

お気づきかもしれませんが、クエリとミューテーションの引数の数が多くなってきま した。多数の引数をうまく扱うために入力型を使ってみましょう。入力型は GraphQL のオブジェクト型と似ていますが、引数に対して使用されるものです。

2015 年の 7 月、このチームは最初の GraphQL の仕様を公開し、JavaScript による参 照実装である graphql.js を公開しました。2016 年の 9 月には、GraphQL はテクニカルプ レビュー版を脱しました。つまり、GraphQL は正式に実戦投入できる状態になりまし た。もっとも、Facebook ではこの時点ですでに、数年間 GraphQL を実際に利用してい ました。今日では、GraphQL は Facebook のほぼすべてのデータ取得に利用されてい て、IBM、Intuit、Airbnb ほか多くの企業で実戦投入されています。

一般論としては、含まれている複数の型がまったく異なるものであれば ユニオン型を利用するのがよいでしょう。同様に、複数の型に共通のフィールドがある 場合はインターフェースを利用するほうがよいでしょう。

すでにお気づきかもしれませんが、tags 配列があるのに対して Tag という GraphQL 型はありません。GraphQL ではデータモデルがスキーマの型と正確に一致している必 要はありません。私たちのクライアントは User 型または Photo 型について問い合わせ ることで、あらゆる写真の中でタグ付けされたユーザーと、あらゆるユーザーがタグ付 けされている写真を見つけることができます。Tag 型をクエリする必要はありません。 クライアントがデータを簡単に照会できるようにするために、タグ付けされたユーザー や写真を見つけるリゾルバを実装したのです。

入力型を使用すると、ミューテーションに渡す引数の再利用性が高まり、エラーが起 こりにくくなります。入力型と列挙型を組み合わせる場合、特定のフィールドに指定で きる入力型をより具体的に指定できます。入力型と列挙型は非常に価値があり、一緒 に使用するとさらに向上します。

GraphQLプロジェクトの肝はスキーマをうまく設計することです。よくできた GraphQL のスキーマはフロントエンドとバックエンドチームの間のロードマップと契約 として機能し、ビルドされた製品が常にスキーマに対応することを保証します。

【本メモ】『情熱プログラマー ソフトウェア開発者の幸せな生き方』

『情熱プログラマー ソフトウェア開発者の幸せな生き方』を読んだので、本メモを公開。

情熱プログラマー ソフトウェア開発者の幸せな生き方

この本は退屈しない人生を送りたいという思いを育むためのものである。
どういうわけか、これから自分のキャリアを積んでいこうというときに、そういう人生を目指さない人がいる。
時流に身を任せていることに甘んじている人は多い。

優れたソフトウェア開発者でもある優れたミュージシャンが大勢いるのはなぜだろうと聞かれる。
偉大になることを望んでいる人のほうが、自分の仕事をこなせばよいと思っている人よりも、
偉大になる可能性がずっと高いからだ。
高い目標を設定すれば、少なくとも平均よりずっと上まで行ける可能性が高くなる。

一番の下手くそでいよう
ぱっとしないバンドとカジノやちっぽけなバーで一緒に演奏していたときには、
その連中と同じような演奏しかできなかった。
しかも、呑んでないのにろれつが回ってないアルコール依存症の患者みたいに、そういうバンドで身に付けた悪い癖がほかの場所で演奏するときにも出てしまった。
こうして僕は、人はどんな仲間と一緒にやるかで腕を上げることもあれば落とすこともあると学んだ。
その上、ある集団との長い付き合いが、その後もずっと人の能力に影響を与えることがある。
この経験で身に付けた習性、すなわち最良のミュージシャンたちを探し求める習性は、
IT業界に移ってプログラマになってからも変わらなかった。
チームで一番下手くそでいるのは、バンドで一番下手くそでいるのと同じ効果がある。
どういうわけか自分自身が賢くなるんだ。
話し方や書き方さえ以前より知的になる。
自分の生み出すコードや設計が以前よりエレガントになり、
難しい問題をますます創造的なソリューションで解決できるようになる。

今すぐ始めよう!
自分自身にとって「一番下手くそになる」状況を見つけよう。
もっと優れた人たちと仕事がしたいというだけの理由で、すぐにほかのチームや会社に移るのは難しいだろう。
だから、良い影響を与えてくれそうな開発者たちと一緒に仕事ができるボランティアのプロジェクトを探そう。
君から見て高く評価できて、自分の目指している「次の段階」の開発者たちがいるOSSを選ぶ。
そのPJのTODOを調べ、何らかの機能やメジャーなbug fixを選び出し、コーディングに励もう。
コーディングの際は、そのPJの周辺コードのスタイルを真似るようにする。
そして、それを楽しむこと。
そのうち、もとの開発者でさえ君の設計とコードを誰が書いたものかわからなくなる。
それくらいPJのほかの部分になじんでいこう。
そして満足のいくものができたら、それをパッチとして投稿するんだ。
出来が良ければPJに受け入れられるだろう。これを繰り返す。

良い人材は新しいものを学ぶのが好きなので変化を追い求める。

今すぐ始めよう!
仮装マシン上でコンパイルし実行するプログラミング言語を使っているなら、
その仮装マシンの動作の仕組みを学ぼう。
ソースファイルのコンパイル時に何が起きているのかしっかり把握してほしい。
入力したコードは、どのようにして人間が読めるテキストからコンピュータが実行できる命令に変換されるだろうか?
自分自身でコンパイラを書くことにどんな意味があるだろうか?
外部ライブラリをインポートすることの本当の意味は?
コンパイラ、OS、仮装マシンは、いくつものコードからどうやって統一のとれたシステムを構築する?
こういう事柄を学んでいくことで、自分が選んだテクノロジの本物のスペシャリストに近づくことができる。

今すぐ始めよう!
1 本当に情熱を持てる仕事を探そう
2 来週の月曜から始めて、2週間分の簡単な日誌をつけよう。
毎朝目覚めたら、自分のやる気の度合いを10点満点で採点するのだ。
毎朝、明日どうやって10点を取るかを考えてほしい。
毎日、昨日のやる気度を記録してほしい。
2週間後、事態が悲観的であれば、大きな進路変更を検討すべきかもしれない。

今すぐ始めよう!
1 「なぜ」「どうして」を考える。
この場で、あるいは次に職場に行ったときに、自分の仕事のなかで完全には理解していないことについて考えてみてほしい。
ある領域をさらに深いところまで掘り下げていくときに役立つ2つの質問がある。
それは「その仕組みはどうなっているか」と「そうなるのはなぜか」だ。
質問に答えることはできないかもしれない。
でも、こうした質問について考えるという行為そのものが、新しい考え方をもたらし、
自分が働いている環境について高い意識を持つことにつながる。
当然これらの質問に答えることで、新たによくわからない部分が出てくることもある。
「なぜ」「どうして」のツリーをこれ以上進むことができなくなったら、十分に分析が進んだといえる。

2 役に立つヒントを探す
いつも使っているツールのなかから、重要だけれどもあまり使い込んでいないツールを選び、それに注目してみよう。
ツールを選んだら、毎日少し時間を作り、そのツールの使い勝手を良くしたり生産性を高めたりする。
何か新しいことを勉強するようにする。

もっと知識があって何でも自分で解決できる技術者になるにはどうすればいいか教えてくれとせっついたところ、
彼はシンプルなレシピを伝授してくれた。
曰く、ディレクトリサービスの構造をよく知ること、
何らかのバージョンのUNIXに親しむこと、
スクリプト言語を習得すること。

クラシック音楽の作曲家も同じことをする。
小説家や詩人も同様だ。
彫刻家や画家もそうだ。
巨匠の作品を研究することは巨匠になるために欠かせないステップだ。

ニュートンの言葉に
「もし私が人より遠くを見ているとしたら、それは巨人の肩の上に乗っているからだ」
というものがある。
ニュートンのように頭の良い人でも、先人に学ぶべきことが多いと認めてるんだ。
僕らもニュートンにならおうじゃないか。

今すぐ始めよう!
1 何かプロジェクトを選び、コードを本のように読もう。
要点はメモに記しておく。
そのプロジェクトの長所と短所を簡単にまとめよう。
そのプロジェクトについて批評を書き、公表してみよう。
自分のコードに利用できそうなトリックやパターンを少なくとも1つ探す。
さらに自分がソフトウェアを開発するときの「べからず」チェックリストに加えるポイントを少なくとも1つ探す。

GEでの仕事は楽しかったが、ある重要な部分が欠けていた。
IT専門家としての僕の技能はある方面において向上するだけで、
企業がどのように運営され、収益を上げ、存続を目指し、革新を起こすかを理解する機会はあまりなかったのだ。
僕はそのことに不満を抱くより、自発的にビジネスと企業家精神を学び、何か自分で行動を起こすことにした。
大学で経営学を履修したこともなかったから、
起業のノウハウを学ぶには泥臭いやり方(つまり、試行錯誤しながら学ぶ)しかないと思った。

信頼できる紹介者を通したことがどれほど重要だったかを僕が知るのは、それからずっと後になってのことだ。
このとき得た教訓は、ベンチャーキャピタリストと接触したければ、
まずは何としても行為的な紹介者を探せ、ということ。
それが最初の足掛かりを得る最良の方法だ。

良いマネージャーの役割は「ピンチヒッター」ではない。
チーム全員の仕事を把握しておいて難しい局面で自分が手伝うのが良いマネージャーの役割じゃないんだ。
良いマネージャーの役割は、チームの仕事に優先順位を設定し、チームが仕事をこなすために必要なものを用意し、
チームがやる気と生産性を維持できるように配慮し、最終的に要求を実現することにある。
チームがうまく仕事をこなすには、マネージャーがうまく仕事をこなせばいい。

目標を持つのはいいことだし、成功を望むのもいいことだ。
でも、さっき言ったようなネガティブで恨み深い人間が成功者になれると思うかい。
まどろっこしく感じるかもしれないが、気持ちを現在に集中するほうが、目標そのものにこだわっているよりも目標に近づけるんだ。

現在見つかっているバッハの最古の直筆の楽譜も、他の作曲家のオルガン曲を写譜したものだった。
ビル・ゲイツがハーバード大学でゴミ箱に捨てられているソースコードを漁った話の方が有名かもしれない。
書き写すことで、筋肉に記憶が残る。
ざっと目を通しただけでは見逃してしまうような、微妙な部分が感覚的に掴める。

今すぐ始めよう!
1 開発日誌をつけ始めよう。
何に取り組んだかの説明、設計上の決定についての理由、難しい技術的/専門的な決定の詳細を毎日少しずつ書く。
たとえ君自身が主な(または唯一の)読み手であっても、文章の質と自分自身を明確に表現できているかという点に気を配ろう。
時には前書いたものを読み返し、批判的な目で分析しよう。
その反省に立って、次にどのように書けばよいかを考える。
日誌を利用することで、文章力も向上し、自分が下した決定に対する理解も深まる。
また、前にやったことの理由と方法を確認する必要があるときにも日誌が役立つ。
2 タイピングを習おう。
入力が楽にできるようになれば、気持ちよく自然に文章を書けるようになる。
もちろん、素早いタイピング方法を習得すれば、これからやることになる作文で時間を節約できる。

自作のコードをリリースしよう
今や人気のある有名なソフトウェアを開発するために大企業で働く必要はない
OSSへの寄与は、君が自分のフィールドに情熱を持っていることの証となる。
OSSへに寄与することは技能の証明になる。
本格的なコードを書き、本格的なプロジェクトに寄与すれば、何かのテクノロジについて知識があると主張するだけよりずっと説得力がある。
誰でもRailsを使えるがRailsコントリビュータを名乗れるのは少数
誰かが君のことを知るようになり、君のソフトウェアがコミュニティに広がるにつれて、君の名前と評判も広がっていく。
要するにマーケティングだ。それこそ君の望んでいるものだろう?

今すぐ始めよう!
ワークショップの大筋は次のようになっている。
単体テストが用意されているOSSを使う。
単体テストをコードカバレッジアナライザにかけて実行する。
テストが最も不十分な部分を探し、そのコードのカバレッジを向上させるテストを作成する。
テストされていないコードは、テストできないコードであることが多い。
そのコードをテストしやすくなるようにリファクタリングする。
変更をパッチとして投稿する。
これの素晴らしいところは、測定可能であり、しかも短時間でできることだ。
やってみない手はない。

大きな目標を立てたら、それを常に見直すようにしよう。
経験から学び、進みながら目標を変更していこう。
最終的に目指すのは、要件の達成ではなく顧客の満足なのだから。
(そして、キャリア設定においては、顧客は君自身だ)

昨日よりよく
小さな変更で全体が大きく変わるというわけではない。
職場でもっと高い評価を受けたいとか、もっと健康な体になりたいとか願っても、
毎日の小さな改善は、目に見える結果に直接結び付かないことが多い。
既に述べたとおり、大きな目標を前にするとやる気が失せるのはそのせいだ。
だからこそ、大きくて困難な目標を目指すときには、毎日その目標に近づけたかは気にせず、
その目標へ向かって昨日より努力できたかを考えることが大切だ。
例えば、僕は昨日より今日のほうが痩せたとはいえなくても、痩せるための努力を昨日より多く実践することはできる。
そうすることによって、自分の行動に満足できる。
目に見える形で自分の行為を着実に改善し続ければ「大きくて重要なこと」を目指す際に僕らを打ちのめす罪悪感と先送りの連鎖にとらわれずに済む。
小さな改善で満足することも大切だ。
「単体テスト」への取り組みの改善」という目標に近くには、昨日より1つ多くテストを作成するだけで十分。
初日がゼロだとしたら、毎日昨日より1つ多くテストを作成するくらいなら続けられる。
そして、これ以上は無理というところまでくれば、「単体テストへの取り組みの改善」は達成しているはずで、
もう改善を続ける必要はない。
これが、作成するテストの数を1日目にゼロから50個にするという計画だったら、
1日目はとても大変になってしまい、翌日からは続けられないだろう。
だから、改善は小さく少しずつでいい。
ただし、毎日行うこと。小さな改善は、失敗の代償も小さい。
1日くらいだめでも、翌日新たに再開できる。
このシンプルな方法のいいところは、プロジェクトの完了やソフトウェアの改善といった当面の目標に使えるだけでなく、
もっと高次元の目標にも使えることだ。
キャリア向上に向かって、今日は昨日よりどんなことを努力できたか?
人脈を1人増やす。
OSSにパッチを投稿する。
ブログに内容のある記事を公開する。
自分の専門分野のテクニカルフォーラムで、昨日より1人多くの人の役に立つ。
自己改善に向かって毎日昨日より少しでも多く努力していけば、
目覚ましいキャリアを築くという途方もなく広大に見えた目標も、だんだん現実味のあるものになるだろう。

今すぐ始めよう!
個人的なことでも仕事関係でもいいから、実行したい困難な改善または複雑な改善のリストを作る。
リストは長くなっても構わない。
次に、リストのそれぞれの項目について、自分自身またはその項目を昨日よりよくするためにどんな努力ができるか考える。
翌日、もう一度リストを見る。
昨日は一昨日より努力できたか?
今日はどうすればもっと努力できるか?
翌日も同じことを繰り返す。
カレンダーにそれを書き込む。
毎朝それについて2分間考える。

【本メモ】『リファクタリング』

リファクタリング』の本メモを公開。

新装版 リファクタリング 既存のコードを安全に改善する

多くの場合、使用するデータを持つオブジェクトにメソッドは定義されるものです。

リファクタリングを開始するとき、最初にすることは常に同じです。
対象となるコードについてきちんとしたテスト群を作り上げることです。
リファクタリングは非常に秩序だっていて、新たなバグを生み出しにくくなっていますが、
人間が作業する以上、間違いを犯す可能性があります。
このためテストは大切で、きちっとした一連のテストを用意するべきなのです。

「メソッドの抽出」
「メソッドの異動」
「ポリモーフィズムによる条件記述の置き換え」
これらはどれも、クラスの責務を分割させ、保守しやすいコードを書くのに役立ちます。

テスト、少しの変更、テスト、少しの変更、と繰り返していくのです。
このリズムによって、リファクタリングはよりはやく安全に行えるようになります。

リファクタリングはソフトウェア設計を改善する
リファクタリングなしでは、プログラムの設計は劣化していきます。
開発者によるコードの変更が短期的なゴールの実現のために行われたり、
設計全体を理解しないままに行われたりすると、往々にしてコードは構造を崩すことになります。
こうなるとコードを読んで設計を把握することも難しくなります。
これに対して、リファクタリングは、むしろコードをきちんと整えていく作業です。
それによって、適切でない部分を取り除きます。
コードが構造を失うと、累積的に悪影響が及びます。
設計が把握しづらくなるにつれて、それを維持するのが困難になり、
急速に劣化していきます。
リファクタリングを定期的に行うことで、コードの状態をしっかりと保つことができます。
設計のまずいコードは、良いものに比べ、同じ処理をするのに余計なコードを書くことになります。
これは文字どおり同じようなコードがあちこちに散らばっているからです。
重複したコードを排除することは、設計を良くする際の重要事項と言えます。
これは将来的にコードを修正することを考えた場合に、見逃せないものになります。
コード量を減らしても、システムがより速く動作するようになるわけではありません。
占有メモリ量に対する節約効果も、大してありません。
しかしコード量は修正時には重要な意味を持ちます。
コード量が増えるほど、正しく修正するのが難しくなります。
ます、理解しておかなければならないコード量が増えます。
その場合、コードの特定部分を変えても期待どおりに動作しないかもしれません。
なぜなら他の箇所でも少し違った文脈で同じようなことをしており、
その部分を直し忘れるものだからです。
重複部分を排除することで、開発者はコードがただの1回のみ書かれ、
そこですべてが処理されることを保証できます。
これは優れた設計のポイントです。

リファクタリングと設計
「設計時には順調に思考が進みますが、実際は小さな穴だらけなのです」
一方で、リファクタリングは事前設計の代わりになるという意見があります。
この考えでは、事前の設計をいっさい行いません。
最初に思いつくままにコーディングして、ともかく動作させ、
その後リファクタリングで形を整えるのです。
実際、この方式もうまくいきます。

確かに、リファクタリングだけでもきちんとしたソフトウェアを作ることは可能ですが、
それが最も効率的なやり方ではありません。
事前設計をある程度行うのが普通です。
さまざまなアイデアを洗い出し、妥当性を考えます。
そして実現可能性のある最初の解決策について見当をつけます。
この実現可能な解決策が浮かぶまでは、コーディングもリファクタリングもしません。
重要なのは、リファクタリングは、事前設計の役割を変えるということです。
リファクタリングをしない場合、開発者は事前に行うのは、非常に工数がかかるかもしれないという不安です。
こうなると、変更の必要を避けるため、事前設計に対して時間を労力をさらにつぎ込むようになります。

リファクタリングを採用すると、力点の置き方が変わってきます。
事前設計は行うのですが、そこで唯一無二の、完璧な解決策を見出す必要はありません。
ここで必要なのは、妥当な解決策なのです。
解決策をコードとして作り込んでいくにつれて、
やがて問題の本質がもう少し見えてきます。
真の解決策は、事前に考えていたものでないことが判明するかもしれません。
しかし、リファクタリングではこれは問題にはなりません。
なぜなら変更にさほどコストがかからないからです。

こうした力点の変化は、設計の簡素化という重大な効果をもたらします。
私はリファクタリングを始める前には、常に柔軟性に富む解決策ばかりを求めてきました。
要求のヒアリングでも、ソフトウェアが使われるにつれて、それらがどのように変化するということを常に気にしていました。
設計の変更は高くつくものだったので、予想できるすべての変更に耐える設計を追求しました。
しかし、柔軟性を求めた解決策は複雑になりがちです。
その結果できたソフトウェアは、予想していた変更に簡単に対処できるものの、
通常は保守しにくくなります。
また対処する場合にも、設計を柔軟にするための工夫をどのように行なっているかを理解する必要が出てきます。
1つや2つではこれは大した問題になりませんが、
変更というものはソフトウェア全体に起こり得るものです。
すべてにおいて柔軟性を実現しようとすると、
ソフトウェアが過度に複雑化し、保守が難しくなってきます。
こうしたやり方では、当然のことですが、
いろいろと工夫した部分が実際には必要とされないという挫折感を味わうことにもなります。
いくつかは役立つこともあるでしょうが、どれが役立つかを予測することはできません。
柔軟性を実現するには、必要以上に大きな範囲での作り込みを強いられるのです。

次は、教訓です。
システムが行なっていることを十分にわかっているつもりでも、
推測はやめて、まず実際に計測をすること。
そこで本質が何かをつかむこと。
十中八九、あなたの推測は間違っています。

パフォーマンスチューニングに、前述の90%の法則を使います。
このやり方では、まずプログラムを整理された形で作り上げます。
そして、チューニングの段階に来て、初めてパフォーマンスを考慮します。
チューニング段階では、一定の手順に従い最適化を行なっていきます。

まず、該当プログラムが、実際に時間とメモリをどのように消費しているかを計測するために、
プロファイラを実行します。
こうすることで、パフォーマンス上のホットスポットになっているプログラムの場所が検出されます。
その後、ホットスポットに集中し、その部分についてのみ、最適化を行います。
こうすればホットスポットに集中できるため、少ない労力でより多くの効果を上げることができます。
ただし、この作業でも注意しなければならないことがあります。
リファクタリングと同様に、変更を小さなステップの積み重ねで行うことです。
各ステップで、コンパイル、テスト、プロファイラによる実行を繰り返します。
もしパフォーマンスが改善しなかった場合は、変更を元に戻します。
満足する水準に達するまで、ホットスポットを見つけては退治していきます。

プログラムの設計が優れていると、パフォーマンス解析の際、より細かな単位へ集中することが可能になります。
プロファイラにより、ボトルネックとしてコードの限定された箇所が示され、
そこを簡単にチューニングできます。コードが非常に明確に書かれているので、どのような選択肢があり、
どのようなチューニグが有効かをより深く理解できるのです。
リファクタリングが速いソフトウェアを作るのに重要な技術
リファクタリングを行なっている段階では、短期的にソフトウェアの動作を遅くしますが、
最適化の段階に入ったときには、チューニング作業を行いやすくします。
最終的には得をすることになるのです。

変更の偏り
私たちは変更がなるべく容易になるようにソフトウェアの構造を考えます。
結局のところソフトウェアはソフトであるべきなのです。
変更しなければならない時には、変更箇所を1つに特定して、そこだけを変えるようにしたいのです。
これがうまくいかないと、密接に関係する2つの不吉な臭いを味わうことになります。
1つのクラスが別々の理由で何度も変更される状況では「変更の偏り」が起こっています。
「DBが新しくなるたびに、いつものこの3つのメソッドを変更しなければならないし、
金融商品を追加するたびに毎回この4つのメソッドを修正している」などということが同一クラスで見られる場合、
クラスを2つに分けた方がすっきりするでしょう。
こうすれば、ある変更要求に対して、対応するクラスが1つだけ修正されることになります。
もちろん、DBや金融商品を実際に追加する要求が生じたあとで、
初めてこの必要性に気づくこともあります。
変更要求に対処するためにはクラスを1つだけ変更し、
バリエーションが増えた時は新しいクラスを追加するというのが望ましい姿です。
「クラスの抽出」で変更の理由ごとにクラスをまとめていくことが重要です。

「変更の偏り」は、1つのクラスがさまざまな変更要求の影響を被る現象であり、
「変更の分散」は、1つの変更がさまざまなクラスの変更を引き起こす現象です。
いずれにせよ、変更とクラスが1対1になるようにするのが理想的です。

### メソッドオブジェクトによるメソッドの置き換え
長いメソッドで、「メソッドの抽出」を適用できないようなローカル変数の使い方をしている
メソッド自身をオブジェクトとし、すべてのローカル変数をそのオブジェクトのフィールドとする。
そうすれば、そのメソッドを同じオブジェクト中のメソッド群に分解できる

### メソッドの移動
あるクラスでメソッドが定義されているが、現在または将来において、
そのクラスの特性よりも他クラスの特性の方が、そのメソッドを使ったり、
そのメソッドから使われたりすることが多い。
同様の本体を持つ新たなメソッドを、それを最も多用するクラスに作成する。
元のメソッドは、単純な委譲とするか、またはまるごと取り除く。
メソッドの移動は、リファクタリングに欠かせないものです。
私は、クラスの振る舞いが多すぎる場合や、クラス間でのやり取りが多く、結合度が高すぎる場合にメソッドを移動します。
メソッドを移動することで、クラスは単純になり、結果として、ひとまとまりの責務をすっきりとした実装に収めることができます。

### フィールドの移動
あるクラスに定義されているフィールドが、
現在または将来において、定義しているクラスよりも、他のクラスから使われることの方が多い。
移動先のクラスに新たなフィールドを作って、その利用側をすべて変更する。
クラス間で状態や振る舞いを移動するのは、リファクタリングの本質です。
システムが発展していくにつれて、新たなクラスや責務の振り直しが必要になります。
ある週では正しく適正であった設計判断も、次の週にはそうでなくなります。
それが問題なのではなく、それについて何もしないことが問題なのです。

### クラスの抽出
2つのクラスでなされるべき作業を1つのクラスで行なっている。
クラスを新たに作って、適切なフィールドとメソッドを元のクラスからそこに移動する。
「クラスは、きっちり抽象化されたものであり、少数の明確な責務を担うべきである」
といったガイドラインを耳にしたことがあるでしょう。
実際には、クラスは成長します。
そうしたクラスには、大量のメソッドとデータがあります。
大きすぎて簡単に理解できないクラスです。
切り出せるところがどこかを考えて、実際に切り出す必要があります。
データとメソッドの一部をまとめて別のクラスにできそうであれば、
それは良い目安です。
他にも、データの一部がよく同時に変更されたり、特に互いに依存する関係にあれば、
それも良い目安になります。

### オブジェクトによる配列の置き換え
配列の各要素が、それぞれ異なる意味を持っている
その配列を、要素ごとに対応したフィールドを持つオブジェクトに置き換える

### フィールドのカプセル化
公開フィールドがある。
それを非公開にして、そのアクセサを用意する。
オブジェクト指向の主要な教義の1つは、カプセル化、あるいはデータの隠蔽です。
すなわち、自分のデータを公開してはならないということです。
データを公開すると、それを所有しているオブジェクトが知らないうちに、
他のオブジェクトから値を変更されたりアクセスされたりします。
これによって、データが振る舞いから分離されてしまいます。
これは、プログラムのモジュール度を下げるので良くないこととされています。
データをそれを使う振る舞いをいっしょにまとめておけば、コードの変更は容易です。
コードの変更箇所がプログラム全体に散らばらず、1ヶ所にあるからです。
「フィールドのカプセル化」の手順は、データを隠してアクセサを追加することから始まりますが、
アクセサしか持たないクラスは、オブジェクト指向の利点を真に活かしていない無意味なクラスであり、
オブジェクト指向技術は単に浪費するだけの恐ろしいものになってしまいます。
「フィールドのカプセル化」が終われば、次に、この新しいメソッドを利用するメソッドを探して、
「メソッドの移動」を適用し、それらのメソッドが荷物をまとめて新しいオブジェクトに引っ越しできないかを調べます。

### サブクラスによるタイプコードの置き換え
クラスの振る舞いに影響を与える不変のタイプコードがある
そのタイプコードをサブクラスに置き換える
タイプコードが振る舞いに関係しないならば、
「クラスによるタイプコードの置き換え」が適用できます。
しかし、タイプコードが振る舞いに影響する場合、
取るべき最善の手は、異なる振る舞いを扱うためにポリモーフィズムを利用することです。
これを行うためには、タイプコードを、ポリモーフィックな振る舞いを実現する継承構造で置き換える必要があります。
この継承構造には、タイプコードに対応するサブクラスを持つクラスが存在します。

### 条件記述の分解
複雑な条件記述がある
その条件記述部と then 部およびelse 部から、メソッドを抽出する
プログラム中で最も複雑なところといえば、複雑な条件ロジックでしょう。
条件判定をして、その結果によって異なる処理を行うコードを書くとき、
よく考えないで長々としたメソッドを書いてしまうことがあります。
メソッドの長さも、コードを読みにくくする要因の1つですが、
条件記述があるとその難しさも増大します。この問題は、コードには、
条件記述部にしろそのアクション部にしろ、何が起きるかは書いてあっても、
それがなぜ起きるのかについてわかるように書いておくのは容易でないという事実から来ています。
どんなに長いコードブロックでも、それを分解すること、そしてそのブロックにふさわしい名前を持ったメソッドの呼び出しで一群のコードを置き換えることによって、
プログラマの意図を明確化できます。

多くのプログラマは、このようなときに条件部を抽出しません。
条件部はとても短くて、そうすることに大して価値があるように見えないからです。
しかし条件部は短くても、そのコードの意図と実体とのギャップは大きいのです。
上のような小さな例でさえ、
元のコードよりは、notSummer(date)と書いてある方が、明確なメッセージとして伝わります。
元のコードでは、それをよく読んで、やっていることを理解しなければなりません。
この例では、さほど難しくないかもしれませんが、それでも、
抽出されたメソッドの方がコメントのように楽に読めます。

### ポリモーフィズムによる条件記述の置き換え
オブジェクトのタイプによって異なる振る舞いを選択する条件記述がある
条件記述の各アクション部をサブクラスでオーバーライドするメソッドに移動する。
元のメソッドはabstractにする。
ポリモーフィズムの真髄は、オブジェクトの振る舞いがその型によって変わるとき、
明示的な条件記述を書かなくてもいいようにすることです。

### ヌルオブジェクトの導入
null 値のチェックが繰り返し現れる
その null値をヌルオブジェクトで置き換える。
ポリモーフィズムの真髄は、オブジェクトのタイプを尋ねてその答えに基づいて振る舞いを呼び出すのではなく、
タイプを尋ねずにその振る舞いをただ呼ぶだけですませようというものです。
そのときオブジェクトは、そのタイプにふさわしい動作を行います。

### オブジェクトそのものの受け渡し
あるオブジェクトから複数の値を取得し、それらの値をメソッド呼び出しのパラメータとして渡している
代わりにオブジェクトそのものを渡す。
パラメータリストを変更に対してより頑強にするだけでなく、
しばしばコードを読みやすくします。
長いパラメータリストは、呼び出す側も呼び出された側も、どこにどの値があるのかを覚えておかなければならないため、
扱いづらいものです。
またコードの重複も招きやすいものです。なぜなら呼び出されたオブジェクトは、
渡されたオブジェクトで定義されているメソッドを使って中間的な値を計算する恩恵を享受できないからです。
しかし問題点もあります。値をじかに渡す場合、呼び出されたオブジェクトは、
その値に対する依存関係を持ちますが、その値を提供したオブジェクトに対する依存関係はありません。
オブジェクトを渡すと、渡されたオブジェクトと呼び出されたオブジェクトとの間で依存関係が発生します。
これが、依存関係の構造を乱すならば、
「オブジェクトそのものの受け渡し」を適用すべきではありません。

呼び出されたメソッドが他のオブジェクトから取得できる多くの値を使用しているということは、
そのメソッドが本来はそれらの値を持っているオブジェクトに定義されるべきだった可能性を示唆しています。
「オブジェクトそのものの受け渡し」を検討するときは、
代替案として「メソッドの移動」も検討すべきです。

### Template Methodの形成
異なるサブクラスの2つのメソッドが、類似の処理を同じ順序で実行しているが、
各処理は異なっている。
元のメソッドが同一になるように、各処理を同じシグニチャのメソッドにする。
そしてそれらを引き上げる

### 階層の抽出
仕事をし過ぎているクラスがある。少なくとも、多くの条件分岐を持つ部分がある。
クラス階層を作成して、サブクラスがそれぞれ特殊ケースの1つを表現するようにする
進化的な設計の立場では、当初はあるクラスが1つのアイデアを実装すると考えていたのものの、
あとになって実際にはそれが2つ3つ、時には10個のアイデアを実装していることに気づくのはよくあることです。
最初はそのクラスも単純に作成されます。
数日後、数週間後には、
1つのフラグといくつかの判定を追加しさえすれば、そのクラスを新しい条件でも使えることに気づきます。
1ヶ月後には、また別の利用方法を追加するかもしれません。
1年後には、フラグと条件分岐があちこちに散りばめられた、ひどい状態になってしまいます。
もし、スイス・アーミー・ナイフのようなクラスに出会ったならば、
物事を単純化して、種々の要素に分解する戦略が必要となります。
ここでの戦略は、条件に対応するロジックがオブジェクトの生存期間を通じて変化しない場合にのみ有効となります。
そうでない場合には、各条件を分離する前に「クラスの抽出」を適用する必要があるかもしれません。

【本メモ】『マネジメント[エッセンシャル版] - 基本と原則』

『マネジメント[エッセンシャル版] - 基本と原則』を読んだので、本メモを公開。

マネジメント[エッセンシャル版] - 基本と原則

  • 短期と長期という観点で、常に事業目的を問い、判断していく
  • 最良の尺度は生産性だが、仕事をしているのは人間である
  • 生産性には、分析・総合・管理・道具が必要
  • 働きがいには、生産的な仕事・フィードバック・継続的な学習が必要
  • これら基盤を整えるのは、マネジメントの責任であり課題
  • 個人/組織が備えるべきは、真摯さ
マネジメントは、常に現在と未来、短期と長期を見ていかなければならない。

企業そのものは、より大きくなる必要はないが、常によりよくならなければならない。
イノベーションの結果もたらされるものは、よりよい製品、より多くの便利さ、より大きな欲求の満足である。

「われわれの事業は何か」を問うことこそ、トップマネジメントの責任である。
企業の目的としての事業が十分に検討されていないことが、企業の挫折や失敗の最大の原因である。
逆に、成功を収めている企業の成功は「われわれの事業は何か」を問い、
その問いに対する答えを考え、明確にすることによってもたらされている。
企業の目的を使命を定義するとき、出発点は一つしかない。
顧客である。
顧客によって事業は定義される。
事業は、社名や定款や設立趣意書によってではなく、
顧客が財やサービスを購入することにより満足させようとする欲求によって定義される。
顧客を満足させることこそ、企業の使命であり目的である。
したがって「われわれの事業は何か」との問いは、
企業を外部すなわち顧客と市場の観点から見て、初めて答えることができる。
顧客にとっての関心は、彼らによっての価値、欲求、現実である。
この事実からしても「われわれの事業は何か」との問いに答えるには、
顧客からスタートしなければならない。
すなわち顧客の価値、欲求、期待、現実、状況、行動からスタートしなければならない。

いつ問うべきか
ほとんどのマネジメントが、苦境に陥ったときにしか
「われわれの事業は何か」を問わない。

この問いは常に行わなければならない。
「われわれの事業は何か」を真剣に問うべきは、むしろ成功しているときである。
成功は常に、その成功をもたらした行動を陳腐化する。
新しい現実をつくりだす。新しい問題をつくりだす。

もちろん、成功しつつある企業のマネジメントにとって
「われわれの事業は何か」を問うことは容易ではない。
誰もが、そのような問いの答えは明白であり、議論の余地はないとする。
成功にけちをつけることを好まないし、ボートを揺することも好まない。

企業の各部門のマネジメントや、企業間のマネジメントを比較するうえで、最良の尺度が生産性である。
入手する経営資源はほぼ同じである。独占というまれな状況を別にすれば、
いかなる分野においても、企業間に差をつけるものはマネジメントの質の違いである。
このマネジメントの質という致命的に重要な要因を測定する一つの尺度が、
生産性すなわち経営資源の活用の程度とその成果である。

生産性の向上こそ、マネジメントにとって重要な仕事の一つである。
困難な仕事の一つである。
なぜならば、生産性とは各種の要因の間のバランスをとることだからである。

戦略計画とは何か
1 リスクを伴う起業家的な意思決定
2 その実行に必要な活動を体系的に組織
3 それらの活動の成果を期待したものと比較測定するという連続したプロセス

まず、あらゆる種類の活動、工程、市場について
「もし今日これを行っていなかったとしても、改めて行おうとするか」を問わなければならない。
答えが否であるならば、
「それではいかにして一日も早く止めるか」を問わなければならない。
さらに「何を、いつ行うか」を問わなければならない。

リスクを伴う意思決定を行いたいか、行いたくないかは問題ではない。
マネジメントは、その責務からして必ず意思決定を行う。
違いは、責任と持って行うか、無責任に行うかだけである。
成果と成功についての妥当な可能性を考慮に入れつつ行うか、でたらめに行うかだけである。

六つの規律
あらゆる公的機関が、次の六つの規律を自らに課す必要がある。
1 「事業は何か、何であるべきか」を定義する。
目的に関わる定義を公にし、それらを徹底的に検討しなければならない。
2 その目的に関わる定義に従い、明確な目標を書き出す。
3 活動の優先順位を決める。
これは、目標を定め、成果の基準すなわち最低限必要な成果を規定し、
期限を設定し、成果をあげるべく仕事をし、責任を明らかにするためである。
4 成果の尺度を定める。
例:ベル電話会社の顧客満足度や、日本が明治のころ社会発展の尺度とした識字率
5 それらの尺度を用いて、自らの成果についてフィードバックを行う。
成果による自己管理を確立しなければならない。
6 目標に照らして成果を監査する。
目的に合致しなくなった目標や、実現不可能になった目標を明らかにしなければならない。
成功は愛着を生み、思考と行動を習慣化し、過信を生む。

仕事をするのは人であって、仕事は常に人が働くことによって行われることはまちがいない。
しかし、仕事の生産性をあげるうえで必要とされるものと、人が生き生きと働くうえで必要とされるものは違う。
したがって、仕事の論理と労働の力学の双方にしたがってマネジメントしなければならない。
働く者が満足しても、仕事が生産的に行われなければ失敗である。
逆に仕事が生産的に行われても、人が生き生きと働けなければ失敗である。

仕事の生産性
生産性向上の条件
自己実現の第一歩は、仕事を生産的なものにすることである。
仕事を生産的なものにするには、四つのものが必要である。
1 分析
仕事に必要な作業と手順と条件を知らなければならない。
2 総合
作業を進めプロセスとして編成しなければならない。
3 管理
仕事のプロセスのなかに、方向づけ、質と量、基準と例外についての管理手段を組み込まなければならない。
4 道具
成果を中心に考える。
さらに基本的なこととして、成果すなわち仕事からのアウトプットを中心に考えなければならない。
技能や知識など仕事へのインプットからスタートしてはならない。
それらは道具にすぎない。
いかなる道具を、いつ何のために使うかは、アウトプットによって規定される。
作業の組み立て、管理手段の設計、道具の仕様など必要な作業を決めるのは成果である。

すでに肉体労働のためのものが、
大きな修正もなしに、情報の処理つまり事務の仕事に適用されることが明らかになっている。
サービスの仕事も、そのほとんどは、物を生産する仕事と大差はない。
肉体労働についての体系的な方法論を適用できるかどうかが明らかでない唯一の分野は、
発明や研究など新知識を生み出すための活動である。
しかし、適用できると信じるにたる理由はある。
 事実、十九世紀におけるもっとも生産的な発明家エジソンは、
体系的な方法によって、発明という仕事の生産性をあげた。
彼に常に、欲する製品を定義することから始めた。
次に発明のプロセスをいくつかに分解し、相互関係と順序を明らかにした。
プロセスのなかのキー・ポイントごとに管理手段を設定した。
そして基準を定めた。

働きがいを与えるには、仕事そのもに責任を持たせなければならない。
そのためには、
1 生産的な仕事
2 フィードバック情報
成果についてのフィードバック情報を与えることである。
自己管理が可能でなければならない。自らの成果についての情報が不可欠である。
3 継続的な学習
知識労働が成果をあげるためには専門化しなければならない。
したがって、他の専門分野の経験、問題、ニーズに接し、
かつ自らの知識と情報を他の分野に適用できるようにしなければならない。
知識労働に携わる作業者集団は、学習集団とならなければならない。
が不可欠である。
これら三つの条件は、働くものが自らの仕事、集団、成果について責任を持つための、
いわば基盤である。
したがって、それはマネジメントの責任であり、課題である。

同じように、企業もある一定の規模と複雑さに達するや、マネジメントを必要とする。
マネジメント・チームという骨格が、オーナー兼企業かという皮膚と交替する。
それは皮膚が進化したものではない。完全な交替である。
複数の人間が協力して、意志を疎通させつつ多様な課題を遂行する必要が出てきたとき、
組織はマネジメントを必要とする。
たとえ製品が優れ、従業員が有能かつ献身的あっても、
またボスがいかに偉大な力と魅力を持っていても、
組織は、マネジメントという骨格を持つように変身しないかぎり、
失敗を重ね、停滞し、坂を下りはじめる。

新しい定義
マネージャーを見分ける基準は命令する権限ではない。
貢献する責任である。
権限ではなく、責任がマネージャーを見分ける基準である。

マネージャーの仕事
二つの役割
1 部分の和よりも大きな全体、すなわち投入した資源の総和よりも大きなものを生み出す生産体を想像すること
自らの資源、特に人的資源のあらゆる強みを発揮させるとともに、
あらゆる弱みを消さなければならない。
これこそ真の全体を想像する唯一の方法である。
事業のマネジメント、人と仕事のマネジメント、社会的責任の遂行という三つの役割も果たさなければならない。
この三つのうち一つでも犠牲にする決定や行動は、
組織全体を弱体化させる。
あらゆる決定と行動は、三つの役割すべてにとって適切でなければならない。
2 あらゆる決定と行動において、ただちに必要とされているものと遠い将来に必要とされるものを調和させていくこと
いずれを犠牲にしても組織は危険にさらされる。
今日のために明日犠牲となるものについて、
あるいは明日のために今日犠牲となるものについて計算する必要がある。
それらの犠牲を最小にとどめなければならない。
それらの犠牲をいちはやく補わなければならない。

あらゆるマネージャーに共通の仕事
1 目標を設定する
2 組織する
3 動機づけをコミュニケーションを図る
4 評価測定する
5 人材を開発する
これら五つの基本的な仕事すべてについて、自らの能力と仕事ぶりを向上させれば、
それだけマネージャーとして進歩する

マネージャーの資質
根本的な資質が必要である。
真摯さである。
最近は、愛想よくすること、人を助けること、人づきあいをよくすることが、
マネージャーの資質として重視されている。
そのようなことで十分なはずがない。

好かれている者よりも尊敬を集める。
一流の仕事を要求し、自らにも要求する。
基準を高く定め、それを守ることを期待する。
何が正しいかだけを考え、誰が正しいかを考えない。
真摯さよりも知的な能力を評価したりはしない。

目標管理
マネージャーたるものは、上は社長から下は職長や専務主任にいたるまで、
明確な目標を必要とする。
目標がなければ混乱する。目標は自らの率いる部門があげるべき成果を明らかにしなければならない。
他部門の目標達成の助けとなるべき貢献を明らかにしなければならない。
他部門に期待できる貢献を明らかにしなければならない。

目標には、はじめからチームとしての成果を組み込んでおかなければならない。
それらの目標は、常に組織全体の目標から引き出したものでなければならない。
組立ラインの職長さえ、企業全体の目標と製造部門の目標に基づいた目標を必要とする。
それらの目標は、短期的視点とともに長期的視点から規定しなければならない。
有形の経済的目標のみならず、
無形の目標、すなわちマネージャーの組織化と育成、部下の仕事ぶりと態度、
社会に対する責任についての目標を含まなければならない。

自己管理
目標管理の最大の利点は、自らの仕事ぶりをマネジメントできるようになることにある。
自己管理は強い動機づけをもたらす。
適当にこなすのではなく、最善を尽くす願望を起こさせる。
したがって、目標管理は、たとえマネジメント全体の方向づけを図り活動の統一性を実現するうえでは必要ないとしても、
自己管理を可能とするうえで必要とされる。
自らの仕事ぶりを管理するには、自らの目標を知っているだけでは十分ではない。
目標に照らして、自らの仕事ぶりと成果を評価できなければならない。
そのための情報を手にすることが不可欠である。

自己管理による目標管理は、スローガン、手法、方針に終わってはならない。
原則としなければならない。
自己管理による目標管理こそ、マネジメントの哲学たるべきものである。

組織の精神
天才をあてにするな
凡人から強みを引き出し、他の者の助けとすることができるか否かが、
組織の良否を決定する。
同時に、組織の役目は人の弱みを無意味にすることである。
要するに、組織の良否は、そこに成果中心の精神があるか否かによって決まる。
1 組織の焦点は、成果に合わせなければならない。
2 組織の焦点は、問題ではなく機会に合わせなければならない。
3 配置、昇給、昇進、降級、解雇など人事に関わる意思決定は、
組織の信条と価値観に沿って行わなければならない。
これらの決定こそ真の管理手段となる。
4 これら人事に関わる決定は、真摯さこそ唯一絶対の条件であり、
すでに身につけていなければならない資質であることを明らかにするものでなければならない。

成果を中心に考える
組織の健全さとは、高度の基準の欲求である。
目標管理が必要とされるのも、高度の基準が必要だからである。
成果とは打率である。
人は、優れているほど多くのまちがいをおかす、優れているほど新しいことを試みる。

人事に関わる意思決定
成果中心の精神を高く維持するには、配置、昇給、昇進、降級、解雇など人事に関わる意思決定こそ、
最大の管理手段であることを認識する必要がある。
それらの決定は、人間行動に対して数字や報告よりもはるかに影響を与える。
組織のなかの人間に対して、マネジメントが本当に欲し、重視し、
報いようとしているものが何であるかを知らせる。

真摯さなくして組織なし
真摯さを絶対視して、初めてまともな組織といえる。

意思決定
日本流の意思決定のエッセンスは5つ
1 何についての意思決定かを決めることに重点を置く。
答えではなく問題を明らかにすることに重点を置く。
2 反対意見を出やすくする。
コンセンサスを得るまでの間、答えについての議論は行わない。
あらゆる見方とアプローチを検討の対象にする。
3 当然の解決策よりも複数の解決案を問題にする
4 いかなる地位の誰が決定すべきかを問題にする
5 決定後の関係者への売り込みを不要にする。
意思決定のプロセスのなかに実施の方策を組み込む。

この基本は、日本以外でも十分に通用する。
それどころか、これこそ効果的な意思決定の基本である。

問題を明確にする
どのような認識の仕方があるかを明らかにすることが、効果的な意思決定の第一歩となる。
意思決定は見解からスタートしなければならない。
異なる見解を奨励しなければならない。
同時に、見解を出す者に対し、その妥当性について徹底的に考えることを求めなければならない。

意見の対立を促す
意思決定における第一の原則は、意見の対立を見ないときには決定を行わないことである。
1 意見の対立を促すことによって、不完全であったり、まちがったりしている意見によってだまされることを防げる。
2 代案を手にできる。
行った意思決定が実行の段階でまちがっていたり、不完全であることが明らかになったとき、
途方に暮れなくてもすむ。
3 自分自身や他の人の想像力を引き出せる。

行動すべきか否か
常に「意思決定は必要か」を検討しなければならない。
何もしないことを決定するのも、一つの決定である。
1 行動によって得られるものが、コストやリスクよりも大きいときには行動する
2 行動するかしないかいずかれにする。二股をかけたり妥協したりしてはならない。

フィードバックの仕組み
1 意思決定の前提となった予測をはっきりさせなければならない
2 決定の結果について体系的にフィードバックしなければならない
3 このフィードバックの仕組みを、決定を実行する前につくりあげておかなければならない

企業活動からリスクをなくそうとしても無駄である。
現在の資源を未来の期待に投入することには、必然的にリスクが伴う。
まさに経済的な進歩とは、リスクを負う能力の増大であると定義できる。
リスクをなくす試みはもちろんのこと、リスクを最小にする試みさえ、
リスクを非合理で避けるべきものとする考えが底にある。
だがそのような試みは、最大のリスクすなわち硬直化のリスクを冒しているといわざるをえない。

活動分析
組織構造に組み込むべき活動のすべてを知る必要はない。
知らなければならないのは、組織の重荷を担う部分、すなわち組織の基本活動である。
1 組織構造の設計は「組織の目的を達成するには、いかなる分野において卓越性が必要か」との問いに答えることから始まる。
2 同時に「いかなる分野において成果があがらないとき、致命的な損害を被るか、いかなる分野において最大の弱点を見るか」
との問いに答えることも必要である。
3 最後に「本当に重要な価値は何か」との問いに答えることも必要である。
組織の基本活動を明らかにするものは、これら三つの問いである。
それらの基本活動が組織の重荷を担う部分、すなわち組織の基本単位となる。

目的と戦略からスタートした基本活動についての活動分析だけが、組織が真に必要とする組織構造を教える。