たれぱんのびぼーろく

わたしの備忘録、生物学とプログラミングが多いかも

0より0.1

たとえ小さく、弱く、欠点が見え見えでも、0.1は厳然たる進歩である.

エラーと人とプログラミング

We Want to Write Logics, NOT to Fix Bugs.

But Human make mistakes.

人は間違う、ゆえに動作確認がいる

  1. 人はエラーを起こす
  2. 人はプログラムを書く
  3. ゆえに、プログラムはエラーを起こす

人のおこなった処理はエラーを含む。
エラーを避ける/直すの仕組みが必要である。

エラーを含まないなら、動作確認 (テスト) なんていらない

バグ、エラー
デバッグ
動作確認
テスト

It’s well known that developers make mistakes during design and code. If developers did not make mistakes, they would have no need to test their code.
Physics of Test Driven Development | James Grenning’s Blog

デバッグにかかる時間

プログラミングの多くの時間は、予期しない動作、つまりエラーを取り除くことに使われる(統計が欲しい)。

qiita.com

blog.livedoor.jp

デバッグとは

バグ・欠陥を発見および修正し、動作を仕様通りのものとするための作業である。
デバッグ - Wikipedia

テストってのはバグを発見するためのものだから、デバッグの一環だよな

gihyo.jp

デバッグ 割合
工数 割合

bug injection
td: discover
bug appear
tfind: find the cause
bug find
tfix: bug fixxing
bug fixed

blog.wingman-sw.com

td ~ changed_code
tfind ~ changed_code ~ td

tdの最小化が非常に有効 == バグの早期検出が重要

  • コーディング時 (td ~ 0)
    • Linter
    • 静的解析 (Language Server等(オンライン型検査))
  • コンパイル
    • 型検査
  • テスト時
  • 本番実行時

最高のデバッガー: コードを書いた瞬間、現在・未来において起こりうるあらゆる種類のエラーとその原因を提示し修正案を出してくれるやつ
要素:

  • ① コードを書いた瞬間: 問題を即座に認識
  • ② 現在・未来のエラー: 潜在的に危険なコード含めて指摘
  • ③ あらゆる種類: 構文・型・アルゴリズム何から何まで
  • ④ 原因の提示: 問題がなぜ起きたかまで提示
  • ⑤ 修正案の提示: 手動バグ取りとの決別

こんな理想的なデバッガーはない.
ただし、部分的に満たす方法はある.

  • 型検査 (①④): コードを書いた瞬間(①)に、現在起きている型エラーを、検査失敗位置と共に(④)示す
  • Lint (①②④(⑤)) : コードを書いた瞬間(①)に、潜在的に危険だと知られている(②)コードパターンの位置(④)を示し、可能であれば修正案を提示する(⑤)

型検査のいい所: 検査に引っかかった場所 (the cause) を明示してくれる => tfindをすごい小さくしてくれる

難しいところ: 単体で導入されるバグは除去が比較的容易。
複合的バグが危ない(トリガーされない危険な振る舞いが起動してしまうような動きが活性化する。それってバグがinjectionされていたってことでは?)
存在するが決して起きないバグはバグか (return より後ろに埋め込まれたバグ)

Lint: 言語仕様が定めるSyntax・Semanticsは満たしているが人々が意図するSemanticsから乖離している(潜在的に危険な)コードを指摘する.

定義域と終域はtdとtfindを縮める効果がある.
td: 組み込まれたテスト(バリデーション)が常時発動するから.
tfind: “契約による設計”で探索範囲が絞れる.
よりcordlessになれば素晴らしい
-> したいことは関数の設計であって、デバッグではない

bug injectionの確率をそもそも下げる.
lint, その他ツール.
=> bug injection自体はされてる。それがリアルタイムで指摘・修正されているだけで

デバッグ比率

テストの工程比率
IPA (2016) "「ソフトウェア開発データ白書2016-2017」ご紹介" p.13 ref

stack overflow (2010) "What % of programming time do you spend debugging?" ref

1 ソフトウェア開発に置いて、デバック、テスト期間を どのく… - 人力検索はてな

早期発見の重要性を示した文献

「多段式エラープルーフ」

定義域と値域の完全なテストに成功し、かつ、完全な関数同士のみをチェーンした場合、全体での無エラー性が理論上保証される。
ちょっとトリッキーに拡張すれば、良くテストした純関数のみをチェーンさせるなら、デバッグコードはプロダクションコードから排除しうる。

デバッグで何をしているのか

なんらかの外部に見える異常が出たら

  • 異常値を取る変数を探す
  • 異常値を生む処理を探す

ソフトウェア工学の大原則: バグ検出はより早期だとうれしい

プロパティ初期化に関わる私の指針

TypeScriptでいうstrictPropertyInitialization

基本的な考え方

classのpropertyが存在するがconstructorで初期化されていない => のちのち必要になると代入される.
coustructor以降は何がどういう順序で実行されるか保証できないので、undefinedなpropertyへアクセスする可能性がある.
=> undefinedがありうることを明示すべき

基本方針

Null安全への指針と同じく、1つのsetとして扱うべきでないものは型を明確に分けて運用すべき.

やり口は以下が有り得そう

  • 未初期化を許容し、型はT | undefinedのUnion型とする
  • 未初期化を不可能とし、Optionモナド型プロパティに対するNoneでの初期化をおこなう

前者の利点はかなり一般的な型システムで完結しているところ。後者はモナド型(なければライブラリ)が必要.
後者はモナドの文脈で綺麗なコードに持ち込みやすい.

各言語での対応

TypeScript

Null安全との兼ね合いもあるので、後者のOptionモナド型を基礎としたい.

Null安全にかかわる私の指針

Null安全とは

実行時にNullを想定しない場所にNullが表れ問題を起こす、ことが起きないと保証された状態.
安全性という意味では、Nullに対する不正演算には例外を投げると言語仕様にある限り、いちおう安全ではあるはず.

基本的な考え

NullとNumber, NullとStringはかなり質が違う.
NullとNumberに共通しない演算はたくさんある.
なのでNullとプリミティブ等を同じset(集合)、プログラミングで言えば型(type)として扱うのに問題があるという立場.

解決指針

Nullと隔離されたプリミティブ型 (いわゆるnon-nullable) を基本とし、Nullable型と明確に区別する.
型システムによる支援でもってNullの紛れ込みを完全に排除できる.
これによりNullなんじゃないかという不安と完全におさらばできる.
Nullable型の実現は言語を取り巻く環境に合わせて柔軟に実現すればいいと考える.
T?のようなプリミティブに対応する各Nullable型を用意してもいいし、Union型とみたり、Option型やEither型のようなモナド型の文脈で扱ってもいい.
なんにせよ、明示しないとNullを扱えない、を基本方針とする.

各言語における方針

TypeScript

strictNullChecksオプションを有効にし、各型がNullを許容しないように強制する (Non-Nullable型を強制する).
Nullableを実現する手法は

  • (build-in) Union型で X | Null にする
  • (fp-ts) Option型 (Either型でも)、すなわちモナド型で処理する

がありうる。
Option型を基本とする方針.

冴えた思考をするには

=> 圧には意味がない。むしろ恐怖の類は思考を遅くする
=> 圧をかけない。伸び伸びと思考できる環境を整える.

  • 時点tにおける思考能力には上限がある

=> 限界突破を任意時点で行うことは不可能.
もし上がったのなら、それは思考を遅くしていた要因を取り除いたからなのでは?
「火事場の馬鹿思考があったんだよ!」という事例に関しては、統計的に考えて欲しい。
その状態に火事場状態と伸び伸び状態で100回ずつ投入されたとしたら、どっちが上手くいきやすい?
確率的な振る舞いをするのだから、1事例ポジティブだったから効果的だ、は無意味.

すなわち、思考能力の面では、伸び伸び状態を実現できるようベストを尽くすほかない。
中期的には成長して思考能力上限があがっていくので、鍛える努力を絶やさないことしかない。
思考能力と思考すべき事柄は別. そっちはそっちで工夫が出来る.

  • やるべき事
    • プレッシャーのない伸び伸びした思考環境を整える
  • すべきでない事
    • プレッシャーをかける
      • 正答を得ないと恐怖・羞恥をうけるという圧
      • 早く答えないとという圧
    • 不安で思考をドライブする
      • 何か手を打たないと、という不安でただひたすら考え込む
        • 不安が思考を冴えなくしてるのに思考し続けちゃう (短期的・極端になりがち)

「プレッシャーをかけられても思考は速くならない。」

プレッシャーをかけられても思考は速くならない。 オラク
PEOPLE UNDER PRESSURE DON'T THINK FASTER. Best regards, The Oracle

from トム・デマルコ (1999) 「デッドライン -ソフト開発を成功に導く101の法則-」伊豆原弓訳. 1版6刷. p196.

f:id:tarepan5884:20190710035023j:plain
プレッシャーをかけられても思考は速くならない