イラスト、プログラミング、文章などは意図が何か? 観察はしたのか?この二つの問いでレビューできてしまう。できることなら問いかけないほうがよい。この二つは終わりがないので誰に投げても刺さってしまう。だが、あまりに質が低いとき、手癖でやっているときに問わざるをえない状況もある。目的が存在する業務ならば、目的とコストのほどよいバランスで両者の探求を打ち切ることはできるが、目的をはっきり認識できていない人にこれを投げると無限の地獄に放り込まれるので、特に注意して使いたい。

redux-sagaのall([fork])パターンは、即座にfinallyに突入してしまう

function* subtask() {
  try {
    yield all([
      takeEvery(action, hoge),
      fork(poyo)
    ])
  } finally {
    if (yield cancelled()) {
      // 後処理
    }
  }
}

subtaskがcancelされたときに後処理が実行されてほしい。ところが、この書き方だとただちにfinallyブロックが評価されます。cancelledはfalseを返すので、後処理はうまく行われません。

yield all([
  takeEvery(action, hoge),
  fork(poyo),
  take(dummyAction),
])

みたいなことをするとfinallyに突き抜けることはありませんでした。

なお、ちゃんとドキュメントに書かれていました。

redux-saga.js.org

There is another popular pattern when designing root saga: nesting fork effects in an all effect. By doing so, you can get an array of task descriptors, and the code after the all effect will be executed immediately because each fork effect is non-blocking and synchronously returning a task descriptor.

Note that though fork effects are nested in an all effect, they are always connected to the parent task through the underlying forkQueue. Uncaught errors from forked tasks bubble to the parent task and thus abort it (and all its child tasks) - they cannot be caught by the parent task.

よかったですね。allの中身が3, 4個くらいならばallを使わずに書くのがわかりやすいかもしれません。

redux-sagaはblocking Effectとnon-blocking Effectの区別が死ぬほど重要です。注意してやっていきましょう。

であること、できること、すること

であること、できること、すること

2019/07/31

 「であること」は、過去のその人の特徴を他者から判断したものになる。例えば日本人である、医者である、社長の息子である、東大生である。これらの特徴は生まれもった環境的特性や、本人の行動によって獲得された社会的地位などの特性がある。

 「できること」は、その人が今できることである。能力に近い特性。東大生であっても高校化学の内容を全く忘れていれば、東大生ではあるが、高校化学ができないことになる。「であること」を達成するのに必要な能力と、今できることは必ずしも一致しない。「できること」は、箸を持てる、浴衣を自分で着ることができる、微分方程式が解ける、というように「であること」と同様の様々な尺度が考えられる。

 「すること」は、将来の自分に対して行動を起こすことである。漫画を読めば同じ漫画を読んだ人と会話ができる。英単語を日々覚えていくと、英語を素早く原語のまま読むことができるようになる。

 これらを総合すると、「すること」が起点となって「できること」が増えて、それを他者に認められることで、「であること」が達成される構造が見える。「すること」と「できること」は、おおよそ個人の行動の範囲内で完結する。また、これらを厳密に区別することにはそれほど意味がない。そして、「であること」はただの結果である。まったくの他人に自分の業績を知らしめて第一印象を良くすることには役立つが、「であること」にしがみついて、しかし、今は何もできない人はたいてい信頼されない。それゆえ、結果の「であること」だけに拘泥するのは意味がない。

 そして、この構造は自信、自己肯定感の問題にもつながる。また、自由の問題にもつながる。「であること」が本質的には無意味であること、これを「であること」にこだわるひとはうっすらと理解している。理解しているが、認めてはいない。それゆえ、不安である。自信につながるのは「できること」である。そして、「できること」は直接的に積極的な意味での自由につながる。「すること」は、将来の自信と自由を培う基盤となる。

 ここで抗しがたい、「できること」を制約する基盤がある。自らの肉体である。老いは「できること」を否応なく減らしてゆく。病気も同様である。あるいは、先天的、後天的な不利益が肉体に降りかかっていることもある。残念なことに、これは生物としての特徴なので覆すことはできない。であるならば、身体に制約されない、できることを増やすのが将来的な自由の最大化につながるのだろうか。知識を使えること、考えられること、これらは肉体の衰えよりは長く保持できる能力であろう。知ることは重要な自由の基盤といえる。

 知ることをしなければ、知らないことを知ることができない。無知の知はそれ自体として重要な性質であるが、自分の無知の具合を知るために知識(経験も含む)が必要になる。知識を得ること、経験をすること、どちらも「すること」である。

 「すること」は何に対してでも可能なのだろうか? しばしば起こる悲劇は、自分の欲求を無視して、他者からの評価、「であること」を想定して、「できること」、「すること」を逆算する事例である。プログラミングに興味がないのにソフトウェアエンジニア「であること」を求める人、患者を癒やすことに興味がないのに医者「であること」を求める人、いくらでも事例はある。もちろん、知識を増やすことは無知を知ることにつながる。なので、興味がおこらない領域の知識を得ることは将来的な糧となる。だが、「すること」はある日少しだけやったら良いものではない。「できること」に繋げるには、「すること」を繰り返し何度も、大量にやっていく必要がある。毎日興味のないことをやるよりは、少しでも興味のある、本当に興味のあることをするのがよいだろう。たいてい、興味のないことをし続けるのは無理だと思われる。

 残念ながら、資本に恵まれない我々は労働をし続ける必要がある。対価の額はおおよそ椅子の種類で決まっている。ここに、興味がなくても「できること」を増やさざるをえない構造がある。我々にとって最適な行動は、「できること」を金銭に変換する効率を上げること、そして労働ではない時間を最大化して、他の「できること」を増やす方針だろうか。興味のある「できること」「すること」が対価を稼げる業と一致している人は幸運である。しかし、実は「できること」が何であるか、興味の対象であるか、は問題ではない可能性もある。「できること」は自信と自由につながるため、自信の基盤を得たあとでは「できること」が何でも良かったと思うのかもしれない。

ソフトウェア設計のための柔軟性とスケーラビリティを考える

ソフトウェア設計のための柔軟性とスケーラビリティを考える

2019/07/15

 

 ソフトウェア設計の目的とは何か。ソフトウェアをお金を儲けるための道具=システムとして作る場合、重要な目的は柔軟性とスケーラビリティである。

 変動し続ける社会環境や、競合によるお金儲けの環境変化に対応するために、柔軟性が必要になる。現実が変わったら収益源のソフトウェアも対応しなければならない。さもなくば、競合に対する優位性が減り売り上げの低下につながる。

 そして、スケーラビリティは自社の市場を広げるために求められる。ここで私が述べているスケーラビリティには二つの側面がある。

  1. ユーザー数が増えて、システムで使うリソースを増やせるようにすること
  2. 市場の拡大に伴って巨大化したソフトウェアの開発と運用が業務として無理なく回るようにすること

巨視的なスケーラビリティ

 システムがサーバーで動いている以上、システムを動かすために物理的なリソースを必要とする。ユーザー数が増えたらサーバーを増やさなければならない。簡単にサーバーを追加できるのならば話は簡単だが、下手な設計をしているとサーバーを増やしてもシステムがスケールしなくなる。

 ここで重要なのは、サーバーが増えても律速しにくい巨視的な設計である。巨視的な設計とは、データベース、アプリケーションサーバー、オブジェクトストレージ、ログ収集機構、メール配信、バッチ処理などの大きな単位でみた部品の結合関係を整理し、あらゆる部品で処理が詰まらないように作ること。

 この設計がなぜ難しいかというと、具体的な実装の細部を無視し、抽象化された部品として整理をしているからである。部品として抽象化するさいに、部品の知識が足りないとシステムはスケールしなくなる。システム全体へ影響を及ぼす重要な特徴を抽象化によって捨ててしまうからである。抽象化は情報を捨てる特徴を持つので、知識の欠如、観点の偏りが決定的なミスにつながる。

 システムをうまく抽象化できたとしても、スケーラビリティを求めるのは終わりがない。factorioisuconで体験できるように、システムを作ると必ずどこかで律速する。律速した場所をチューニングしても、また別のところが律速する。現実的にはどこかで妥協をする必要がある。

機能の複雑化と戦うスケーラビリティ

 二番目の問題。ソフトウェアが巨大化すると言っているが、なぜ巨大化するのか。ユーザーに見せるUIはユーザーの目的に対して一直線に問題を解決するものが理想だ。シンプルに作れるならばそれが一番よい。だが、たいてい複雑化して巨大化している。なぜなのか。

 ユーザーの目的が複数あるケース、これはどうしようもない。開発し始めた当初は大雑把に認識していた目的が実は人によってバリエーションに富んだ目的だった。タスク管理ですら、ユーザーの立場や業種、知識に応じて目的が違うはずである。これがタスク管理システムが乱立する理由である。ともかく、このように大きな領域で仕事を始めると見えていなかった目的が乱立することがある。この場合にはすべての目的を需要に応じた妥協をするとはいえ、リソースの許す限りすべての需要を満たしたくなる。

 それゆえ、画面は複雑化し機能は増え続ける。市場規模、ユーザー数が拡大すると、これは避けられない。何故なら、人間は自分の目的に完璧に合致していなくても、便利な道具があればそれを使うから。システムの意図した目的と人間の目的が完璧に合致するならば、システムに変更は入らないが、少し目的のずれた場合には変更の要求が発生する。最初は心地よく使えていても、日常的に繰り返し使うことによって、この目的のずれが体験の悪さとなって現れる。なので、ユーザーを増やさなければならない資本主義の仕組みに乗る以上は、ユーザーの目的が多様化することを避けられない。よって、システムは複雑化してしまう。

 本来ならば、機能が増えすぎたらそれを整理して圧縮するのが望ましい。機能ごとに利用頻度の統計をとるのもよいだろう。だが、似たような目的を複数の機能で実現しているシステムはあまりに複雑化しすぎている。ここで、機能を統合して減らす決断が必要になる。たいていの人は機能、コード、部品を増やすことは簡単にできる。だが、減らすのは難しい。増やすことによって発生する責任は軽いが、減らすことによる責任は重い。確固たる思想を持って、このシステムの本質的な目的は何なのかを見定めておく必要がある。

 また、管理画面の機能が増え続ける問題もある。ユーザー数が増えると、サポートやお金の管理、監査、データ収集などの管理画面を使う社内の人間のための機能が増える。これらは自動化されていることが望ましい。それが会社の利益率に直結するからだ。こちらもユーザー数が増えるにつれて機能が増えて複雑化する。規模が小さいうちはラフなデータを出力して、人間が加工をすればよいが、組織の拡大とともに規模が大きくなると、専用の自動化が必要となる。

 

 以上観たように、広い意味でのスケーラビリティを完璧に満たすのは難易度の高い設計が求められる。管理機能まで含めた全体を見渡す立場の人がいれば、まだましだが、機能ごとに担当者、チームが別れていると全体の調和を目指すのは難しくなる。こうしてコミュニケーション能力が求められる。人間のコミュニケーションが増えると、それもそれで組織のスケーラビリティを阻害する要因となる。これはまた別の話ができるだろう。

 

まとめ

  • お金儲けのためのシステムは、会社が存続し続けるために柔軟性とスケーラビリティを備えたシステムを作る
  • スケーラビリティは巨視的なスケーラビリティと機能の複雑化と戦うスケーラビリティがある
  • 巨視的なスケーラビリティは開発者にとってお馴染みのシステム構成の話で、抽象化の漏れが致命的になる
  • 機能の複雑化は市場の拡大によって確実に引き起こされる
  • システムを運用するための社内の組織、システムを運用するためのシステムが増える
  • 人間がシステムを作る以上、人間と人間のスケーラビリティも視野に入る

おまけ

 つまり、システムの設計とは何なのか、何をしているのか。これはお馴染み問題解決能力と同じもので、「目的と制約を明確に認識して、目的を満たす最小コストの方法を見つける」ことである。目的は法人の場合は法人の維持、つまり利益率の維持、よってお金儲けであり、制約はソフトウェア技術、ハードウェア、人間の能力、法律などである。

 規模の拡大は外部からの要請によって求められる。投資家や株主など。資本主義は投資対象が毎年成長することを求めるシステムなため。

 柔軟性とはスケーラビリティを満たすために必要な性質なのではないか、この疑問も出てくる。おそらく正しい。柔軟性はシステムの目的でありスケーラビリティのための手段でもある。これを考えるには柔軟性も詳しく分解していく必要がある。素描しておくと、

  1. 柔軟なところと変わらないところの区別
  2. 変わりやすさを見抜く未来予知の話
  3. 未来予知に必要な広い教養の話

あたりだろうか。

マイクロサービス雑感

 マイクロサービスとは複雑さを分解することでスケーラビリティを確保する構成である。もちろん、複雑さを分解しても全体の複雑さは変わらない。人間にとっての複雑さであり、これは依存関係のコントロール、責務の整理である。責務への分割がまさにマイクロサービスである。これの規模が大きいので組織の話と関わる。スケーラビリティには量に関するスケーラビリティと複雑さに関するスケーラビリティがある。複雑さで律速されると、量のスケーラビリティの話まで展開ができない。複雑であるほど、スケールしにくくなる。シンプルであるとスケールしやすい。量の問題にできる。

 責務の単位へシステムを分割したことで、依存関係はどこへいったのか? 本質的なサブシステム間の依存関係は残ったままである。これに対して負荷がかかり、サービスがスケールすると、ボトルネックになる場所がシステム間でたらい回しにされる。チューニングをしていると、ボトルネックの箇所が変化していくあれである。依存関係はなくなっていないので、どうやっても負荷の影響は受けてしまうのだ。だが、サブシステムに分割していることで、サブシステムの責務の範囲内でRedisを新設し、サービス呼び出しをキャッシュできるかもしれないし、現実的なスロットリングのルールを協議できるかもしれない。

 もちろん、組織として彼の受け持つシステムの責務に閉じてしまい、サイロ化してしまうかもしれない。マイクロサービスの組織では、全体性を認識しながらシステム間プロトコルの調整をしなければならない。これを各システムの実装者に求めるのは、全体が小さいうちなら現実的だ。だが、全体が100人の組織になったらもはや専門の全体設計者が調停をやらないとスケールしなくなるのではないか。もちろん、ここまで大きなシステムを維持できているのであれば、その商業的な価値は高いものだろう。当然、その責務を帯びた視野の広い人間がいて然るべきだ。

 いろいろ考えたが、結論としてはつまらないものになる。古来よりシステム設計の勘所はずっと同じである。シンプルな部品で作る、それだけである。クラウドコンピューティングの力によって、サブシステムを作りやすくなったからマイクロサービスが登場してきたのだろうか。だが、誕生の経緯が何であれマイクロサービスの設計と、メンテナンスしやすくスケールしやすいソフトウェアの設計は同じ観点が求められる。全体性の認識と明確な責務*1への切り分けである。果たしてこれをできるようになるにはどうしたらよいのか。本質看取の能力は何によって磨かれるのか。

*1:明確な責務へ分けられると自動的にシンプルさが得られる

会話で情報が増えるとうれしい

 オープンクエスチョンで言われるような、よい質問は、(会話の場の?参与者たちの?)情報*1を増やしてゆく性質をもつ。会話は情報をやりとりするものであり、情報が増えると目的*2が達成される。会話、とくに雑談をするときにはいかに情報を増やすか考えながら発話すると良いのかもしれない。その一つの手段が自己開示や開かれた質問でもある。はい/いいえで答えられる質問はむしろ情報量が減っている。曖昧な状態から一つの状態に収束しているから。たしかに知識は増えているが、自己開示を促す質問よりは、情報量の増える会話ではない。

 発話が多ければそれでよいのだろうか? 当然そんなことはない。長広舌は嫌われるし私も嫌いだ。やりがちだが。なぜ駄目なのか。長い発話を理解するのは認知的にたいへんだからだ。理解できなくなった時点で、それ以降の発話は聞き流される。つまり、伝わらない発話は相手の情報を増やさないために、会話の目的が損なわれる。なにより効率が悪い。もちろん、知識や体験の基盤が共通で、慣れ親しんだ間柄ならば長広舌を用いてもよいのかもしれない。

*1:ここでの情報には、言葉で示された意図や事実の伝達だけではなく、非言語情報もある。身振りや表情、手足の態度はわれわれの想像以上に情報を送出している。

*2:もちろん、会話の目的は情報のやりとりだけではない。相手を認めることで、親密さを増やすことも重要である。

なぜソフトウェアエンジニアの私が哲学をやるのか

 なぜなのか。それは、哲学が役に立つから。ちょっとわけがわからないと思うので、順を追って説明します。

 ソフトウェアエンジニアは何をしているのでしょうか。まずはこの問いからです。ソフトウェアエンジニアは、計算機科学、つまりソフトウェアの設計と実装そして運用の技術で仕事をします。主な用途は自動化されスケールするシステムの構築です。ではこのシステム、ソフトウェアエンジニアがつくるシステムは何のためのものなのか。たいていは実社会の問題を解決するために作られます。会計システムであれば、会計の効率化、自動で計算や仕分けをしてくれたり、ですよね。ソフトウェアエンジニアは実社会の問題をソフトウェアによる自動化の力を借りて解決します。ここまでは簡単ですね。

 それでは、彼らは何を作っているのかみていきましょう。実社会の問題を解決するシステムとは何なのか。これは具体化するときりがないものですが、いくつかの特徴があります。まずは定型的な処理であること。つまり、ルールが決まっている性質のことです。税の計算や商品の購入のルールは短期的には一定ですよね。つぎに、たくさん行われる処理であること。税金の計算も買い物もたくさん行われますね。繰り返し行われる業務を自動化すると人間はほかのことをできてめでたいですね。柔軟性が要求されないものから自動化されてゆき、効率的になってゆきます。

 さて、ルールが決まっていてたくさん行われる処理、これは何なのでしょうか。計算機誕生以降にできたものなのでしょうか? 違いますね。計算機が誕生する前からあったはずです。その頃は人間が計算して、処理していました。つまり、当時はシステムを人間が運用していたといえます。ソフトウェアエンジニアは社会のシステムを実装して自動化しているだけです。

 余談ですが、この自動化が資本主義と組み合わさると莫大な利益をもたらします。商売をするにあたり、利益はどうやって決まるのでしょうか。単純化すると利益率と売った数のかけ算ですね。利益率を上げるのは人件費などの難しい問題と限界がありますが、販売数は数十億人オーダーまでスケールする余地があります。つまり、どれだけスケールするかによっても利益の量が左右されます。コンピュータ誕生以前は、人間が商売のシステムを運用していました。ところが、このシステムが自動化されたことにより、スケーラビリティが桁違いに伸びたのです。これがサーバー屋さんでスケーラビリティが重視される理由です。根源的に、データベースでスケーラビリティが律速しやすいのですが、その限界は人間が運用するよりはよっぽど大きいのです。GAFAMが注目され、実際に莫大な利益を生み出しているのは、億オーダーまでスケールするシステムを構築したからですね。

 脱線しました。つまりですね、ソフトウェアで自動化されようとされまいと、システムはあるのです。会社にも役所にもシステムはありますし、法律だってシステムです。システムとは何なのか説明するのを忘れていました。これはルールの集合です。ここでは、実社会に適用されるルールを指しています。システムは数千年前にだってあります。租税制度は古代からありますね? 人間が運用するシステムであれば、それは社会がある限り存在してきました。これを自動化することに、ソフトウェアの価値があるのです。

 ソフトウェアエンジニアとして賃金が得られているということは、何らかの必要とされるシステムを自動化していることになります。これは疑いようがありません。ですが、このシステムはソフトウェアがあろうとなかろうと存在します。システムの仕様、ルールそのものは計算機の外の世界にあります。なので、ソフトウェアエンジニアが計算機科学および仲間内の知識に閉じこもっている限りは避けがたく仕様に襲われます。仕様変更にも苦しめられます。

 だから、計算機の外の、実社会のことを知らなければよいシステムは実装できません。社会のことを知らないばかりにまずい設計をして、仕様変更も増えます。仕様を決める人がそこを説明しろやという話もありますが、これはおのおのの現場における政治の問題でもあるのでおいておきます。ソフトウェアエンジニア「も」社会を理解しておくことで、給与交渉としましょう。そして、実社会は人間と慣習の集合でできています。慣習は法学、政治学社会学などによって研究されています。人間そのものは哲学や人類学が研究をしています。

 今までにないシステムを作っているという意見もあるでしょう。ですが、この新しいシステムも実社会プラットフォームのうえで動いています。実社会プラットフォームは自然プラットフォームおよび人間たちプラットフォームのうえで動いています。Appleのプラットフォームで稼ぐものはiOS更新のしきたりに従わなければなりませんね? 同様に、どんなシステムを構築してもそれは基盤側に左右されてしまいます。ですので、実社会および人間の理解は役に立ちます。自然プラットフォームもございますので、科学の基礎的な勉強も当然有用でしょう。

 脱線はじまり。これは私の経験則ですが、学習という投資では基本的な知識ほどリスクが低い特徴があります。古いものほど役に立つといってもよいですね。多くの人は新しいものに飛びつきますが、新しいものほどリスクは高く、たくさんの新しいもののうちどれが残っていくのかは誰にもわかりません。未来予知できた人はすごいですね。今後も未来予知にかけるのもありでしょう。ですが、古いのに今でも残っているものは社会変化に耐える安定性を持っています。破壊的イノベーションで、古いものが倒されることを指摘する人もいるでしょう。ところが、破壊的イノベーションは古い知識が倒されたのではなく、古い知識から脱することのできなかった人間たちが倒されただけです。イノベーションの文脈でなくとも、柔軟性がないものは淘汰されてゆきます。脱線おわり。

 実社会の人間と慣習を研究する学問は人文科学だとか社会科学と言われます。人文科学の部分集合が社会科学だとか読んだことありますが、ジャンルの名前はどうでもいいです。重要なのは、社会の慣習と人間を知ることです。題では哲学をあげましたが、じっさいには社会学や法学をやるのもよいでしょう。私もいろいろ手を出しています。ただ、その中でも哲学は格別です。古典として残っている哲学書は思考が深くて、考えれば考えるほど発見がありますし、前提から疑いつづけ判断を留保する態度を得るのも有用です。前提や自明性を疑う態度は、デバッグやサーバー障害で役に立ちます。おもしろいことに哲学の内容は抜きにしても、思考様式が非常に実用的です。そもそもソフトウェアエンジニアの皆さんはプログラミング「言語」を操りますが、言語って何かわかっていますか? なぜ変数の名前にこだわるのが重要なのですか? 私にはまだまだわからないことだらけです。答えられません。ですが、人間と言語について勉強すると答えに近づけるのは間違いないです。

 疲れてきたのでまとめます。ここまで読んだ人はお疲れ様でした。いいたいことは、「ソフトウェアエンジニアとしてお給料をもらっている人は、実社会のシステムを実装しているはずなので、社会の勉強にも投資するとスーパーエンジニアになれるよ」です。なれるかは知りません。ですが、よい設計ができるようになります。デバッグもかなり強くなります。

 え?人間と関わりたくないからソフトウェアエンジニアをやっている? そうですね、私もそうです(そうでした)。でも読書は一人でできますよ。まずは興味のわいたジャンルからどうぞ。