英語勉強法について

思ったことをとりあえずメモするプレイスホルダー。思い付きやネイティブのESL教師に聞いた方法など。

  • あらゆる学習法に共通する学習効果の法則。
    • 最も効果が高いのは、学習前にできなかったことが学習後にできるようなるという学習。*1
    • 感覚的に腑に落ちているかどうかが学習効果に比例する。*2
    • 最も効果が無いのは、意識が受動的になっている学習。*3
  • 感情の高さと学習効率は比例する*4
  • 学習意欲の維持が重要。*5
  • 学習方法による学習効率の違いは大きい。自分の現在の能力に合った学習法を随時選択するのが重要。*6
  • 文法の雰囲気読みは厳禁。単語の雰囲気読みはアリ。*7
  • 英語に慣れる訓練1
    • 方法
      1. 自分なりに流暢に発音できる長さの文章(節や1文でも良い)を選ぶ。(英会話のフレーズでもニュース記事でもなんでもOK)
      2. 文章の先頭から精読する。その際、日本語に翻訳しないように注意する。単語レベルでどうしても日本語が思い浮かんでしまう人はなるべくそれを抑制することを意識しながら進める。しかし、語順を変えて理解するのは厳禁。精読できなかったらその文章はスキップして次の文章に進む。
      3. 目の前に話し相手やプレゼンの聴衆がいるのを想像しながら、身振り手振りを行い表情や声の抑揚を意識しながら実際に声に出して読む。声とボディランゲージに自分の意思が乗ったと感じたら次の文章に進む。5分やってみてもうまく行かなかった場合も次の文章に進む。
    • ポイント
      • 脳内活動も筋肉の活動も神経活動であり、思考、表情、口周辺の筋肉、発音、声の抑揚、ボディランゲージ等が正しく連動している状況を神経に記憶させるのが狙い。そのため、感覚レベルで理解できている文章のみを扱い、そうでない文章はスキップするのが重要。
  • 英文を順番に理解する訓練1
    • 方法
      1. 自分の興味のある文章(書籍や新聞記事など)を選ぶ。
      2. 声を出さずに文章中の1単語を見る。
      3. 『その単語の意味』と『その単語までの一連の意味』が
        • 『その単語まででは意味として成立しない』と思ったら、次の単語に
        • 『感覚的』に理解できたら、その単語を『声に出して』発音し、その単語までを隠す。
        • 『感覚的』に理解できなかったら、『精読』して理解し、隠していた文章を戻して再度挑戦する。
      4. 1つの文の意味が理解できたら次の文に進む。
    • ポイント
      • 自分の実力で辞書を使って1分以内に『精読』できない文が1ページ平均で最大2文以内のものを選ぶ。そのような文章が見つからない場合は文法学習をしましょう。
      • 『精読』は厳守。単語から推測する雰囲気読みをしてしまうとこの学習は全く意味がなくなる。自分でも雰囲気読みかどうかわからない場合は、料理のレシピを読みながら頭の中で調理をシミュレートするのがおすすめ。*8
      • 文章中の1単語を見て、単語を認識し、文脈から意味を推測し、意味を感覚的に理解する、という一連の行為に時間設定をしないようにする。
      • 精読は数分程度の制限時間内に行い、精読できなかったら頭を切り替えて次に進む。ネイティブでも感覚的に理解できるが『精読』できない英文は多い。ここでこだわって停滞してしまう人は人生という制限時間内に英語が使えるようにはなれない。
      • 次の単語のみを表示してそれ以外全てを隠すという方法は逆効果。科学的な裏付けはないが、おそらく人間は、一瞬で文全体の構造の先読みと、直近の数単語の先読みを行い、推測の精度を上げていると思われる。
  • 英文を順番に理解する訓練2
    • 方法
      • 訓練1を行いつつ、句や節や文の単位で空で発音する。*9
    • ポイント
      • 訓練1では自分でも気づかないうちに雰囲気読みをしてしまうことがあるが、この方法では雰囲気読みが通用しづらい。
      • 部分的に単語が変わっていたとしても意味が同じで文法的に正しい文章であればOKと割り切るのが重要。*10
  • リスニング訓練1
    • 注意点
      • 頑張らないこと。頑張ってしまうとそれがストレスとなり、学習意欲が減退してしまう。難しいと思ったら即座にあきらめて次の文に進むようにすること。
    • 方法
      • 繰り返し聞くことが可能な英語のセンテンス発音を用意する。アメリカ英語ならCNNやイギリス英語ならBBCのようなクリアな発音がおすすめ。
      • 精読して意味を取る。一般的な構造の文なら普通に精読し、言い回しなどは丸暗記でも構わない。和訳はしないように注意する。
      • 音を聞きながら、1文もしくは一呼吸分の発音をすべて認識できるようにする。
      • 音を聞きながらある程度流暢に発音できるまで練習する。自分の声を聴きながらオーバーラッピングできるようにする。
      • 音を録音して自分の声と教材の音声の違いを確認しながら、違いが感じられなくなるまで繰り返す。
    • 備考
      • 学習内容は完全に発音訓練だが、これがリスニングの訓練になる。
      • リスニング能力の向上のためには、おそらく純粋に音を聞き分ける訓練をする必要はほとんどない。マイ・フェア・レディに出てくるヒギンズ教授のような形で言語学を研究したい人は別だが。
      • 純粋に音を聞き分ける訓練が必要ない理由は、第一に、音を聞き分けられたかを確認する学習教材を十分な量調達するのは現実的ではないということ。音を聞き分けられたかをチェックするためには、教材は完全な使い捨てになる。繰り返し使ったら、それは聞き取れたのか前に学習した記憶が残っているのかを判断できない。第二に、リスニング能力と音を聞き分ける能力にはほとんど相関が無いと思われるため。例えば、ネイティブであれば、なまりがあっても、騒音の中でも、音が微妙に途切れる電話回線で通話しても、食べ物をほおばりながら会話をしても、大抵は聞き取れる。また、早口になると音が替わったり抜けたりするケースも多い。つまり、正しい英語発音と大きくかけ離れていても英語として把握が可能と言える。*11重要なのは、リズムと音節と抑揚と状況からの推測。推測をするためには状況に合った文を自分で作り出す作文能力が重要となるのだが、これはこの訓練で鍛えることができる。また、リズムと音節と抑揚もこの訓練で鍛えることができる。
      • この訓練の成果がある程度実ってきたら、リスニングに特化した訓練をあえて設ける必要は無い気がしますね。これ以上の英語能力は恐らくノンネイティブとして通常の範囲を超えているので。CNNなどを当たり前のように精読レベルで聞き取れてシャドーイングやリピーティングでノンネイティブとしては完璧なレベルで発音できるのだから、これ以上リスニングの訓練をする必要性は考えづらい。
  • リスニング訓練2
    • 前提条件
      • 英語ニュースに出てくるレベルの文章を精読可能な英語力。*12
    • 注意点
      • 頑張らないこと。頑張ってしまうとそれがストレスとなり、学習意欲が減退してしまう。難しいと思ったら即座にあきらめて次の文に進むようにすること。
    • 方法
      • 繰り返し聞くことが可能な音源(ニュースやドラマなど)を用意して、とにかく聴きまくる。
      • 明らかに先頭から最後までを順番に自然に理解できたと直感できた場合はその英文はOK。それ以外の場合は紙に書き出すなどしながら厳密に意味を調査し、聞き取りにくかった部分を感覚的に聞き取れるように感じるまで何度も繰り返して聞く。
  • 英語リスニングがうまく行かないケースと対策
    • そもそも文字で見せられても精読できない。→ 精読の練習が必要。リスニング練習は効果が無く純粋な時間の無駄。
    • 音声自体の聞き取りができない。→ 短い文章の反復リスニングが効果的。市販のCD付のセンテンス集などが便利。1つのセンテンスに対して、精読、シャドーイングが必須。リピーティングやオーバーラッピングまでを行うと効果は劇的に高くなるが、10回程度の反復で打ち切らないと効率とモチベーションの低下をもたらすので注意。
    • どうしても聞き取れない音があって文章を構成できない。 → 音を完全に聞き取るのはネイティブでも不可能。そもそも音が元から落ちているケースが多い。英文を頭から単語解釈・構文解釈・意味解釈できる能力があれば情報落ちを補完できる。説明的な文章を確実に頭から解釈する練習が必要で、ニュースや技術書などを返し読み禁止で確実に精読する練習が有効。これができるようになると、勝手に聞き取れない音を補完できるようになる。実際問題、used to のように d と t がつながる箇所の d が消えたり、前置詞が全く聞こえなかったりすることは多く、ネイティブはそれを無意識レベルで脳内補完して対応している。
    • 文章を構成できる能力があるのに速度についていけない。→ まずは高速に精読できる能力があるのかを疑う。TOEICの公式問題集で初見のPART7を45分でほぼ全問(54問中52程度)正解できないようであれば、リスニング学習は必要なく、精読で速く読む練習が必要でありリスニング学習は完全な時間の無駄。PART7で上記制約をクリアできるのであれば、ひたすらリスニング練習して慣れればよい。ひたすら聞く練習と、聞き取れなかった文章を抑揚や感情まで再現する形でシャドーイングおよびリピーティングする練習が有効。(ここまでできれば、後はひたすらニュースでも映画でも日常会話でも経験しつつ、単語や言い回しなどを習得していけばよい。)*13
    • ※上記に関して、精読能力は必要とするが、英作文能力は必要ない点が重要。和文英訳形式の英作文学習は『翻訳』という特殊技術の学習になってしまううえ、日本語を最初に意識するため、英語脳を作るためには極めて良くない方法と言える。ただし、フレーズの丸暗記は有効。なぜなら、フレーズを繰り返して学習するうちに、日本語の文章を見た瞬間に、頭の中でまだ憶えている内容が取り出され、それを英語に変換しようとするので、和文英訳ではなくなる(和文の塊が1つの記号として扱われる)。ということで、日本語の文章が表示されてから2秒以内程度で10単語以上の英文をスラスラ発話し出せるような形でフレーズの丸暗記をするのは有効。
  • 公式本(新公式とL&R全部) TOEIC Part7 を使った学習法(案)
    1. 精読
      • 公式本の Part 7 の問題文と設問をすべて精読する。
    2. 音読速読
      • 公式本の Part 7 の問題文と設問をすべて音読かつ速読する。
      • ひとまとまりの問題文を音読速読の1単位とし、文字は基本的に全部読む。
      • 1単位について、毎回時間を記録する。1単位を連続して繰り返し、タイムが伸び悩むようになったら、当日の最速時刻のみ記録に残し、次回の基準タイムにする。
      • 発音はすべて事前に確認(人名や地名も全部)したうえで、自分が納得のいくレベルの発音を行う。
      • 1単位を頑張りすぎないようにする。同一の問題単位を数回速読して伸び悩んだら速攻で次の問題単位に移動する。
      • とにかく限界まで高速に発音する。
      • 最初は目で追いながら読むのがやっとだが、慣れてくると、見た瞬間に発音するよりも、チャンクで理解した時に発音したほうが、間違えず、速く、そして流暢に読めるということがわかってくる。そうなったら、チャンク読みに切り替える(おそらく一時的にタイムは悪化する)。
      • チャンク読みにも慣れてくると、目はかなり先読みしているのに口が追い付かない状況になる。音読速読が250wpmを超えてそれ以上伸び悩む状態になったら、黙読に移行する。
      • Part7の文章を400wpm以上になるまで続け、その後は、初見の VOA LE の文章を、意味を理解しつつ確実に 300wpm 以上で読めるかどうかを時々試し、実現できたら学習完了。

*1:知らなかったことを知る、できなかったことができるようになる、という類のもの。忘れたりできなくなったりすることについては全く気にする必要は無い。なぜなら、忘れたりできなくなったらまた学習するというのを繰り返すのが王道だから。

*2:たとえば、初心者が映画のセリフを学習する場合、自分のレベルに合わない難しいセリフをどれだけ学習しても意味がない。全く無意味とは言わないが、正しい順序の学習の1%以下の効率であると考えたうえでやったほうがいい。

*3:たとえば、聞くだけで英語が喋れるようになるというような教材は、学習中の意識の在り方により学習効果が全く異なる。ダメなケースは、ながらで聞く場合。学習効果はほぼ0と思ってよい。ダメでないケースは、意識的に、文法の調査、文章を頭から理解する努力、シャドーイング、リピーティング、オーバーラッピングなどを行っている場合。

*4:英語が通じて嬉しかったり、英語がうまく話せなくて恥ずかしい思いや悔しい思いをしたりするのが劇的に有効。英語に限らず学習全般において、人間の脳はおそらくそういうようにできている。

*5:嫌な勉強法で英語が嫌いになるよりも好きな勉強法のほうが良い。

*6:英語初心者なら、CNNを毎日10時間1年聞くより初心者用の本を1冊読んだほうが確実に上達する。仮に本1冊5時間で読めるとすると、その最初の5時間に限れば、前者と後者では学習効率に730倍以上の差があることになる。

*7:そもそも単語に関してはネイティブでも雰囲気読みをしているし、厳密な意味など存在しない。単語自体が抽象化の産物なので、発言者本人の意図するものを正確に表現することは本質的に不可能。日本人が日本語を読む時も、人によって単語の捉え方は異なるし、間違って覚えていることもある。単語の厳密な意味という幻想はネイティブ並みの英語力になって英語教授法が必要とされる職業などに就いた場合にのみ考えればよく、そうでない人は、単語の意味を現状より正しくもしくは詳しく知りたくなった時に英英辞書で調べるのが正解。しかし、文法の雰囲気読みは不可で、これをやると英語的な感覚から逆に離れていってしまうこともある。単語は読み飛ばしていても何度もいろんな文脈で同じ単語を見ていれば感覚的に体に染み込んでいくが、文法は精読して理解しないと学習効果が得られない(パターンを自然に学習するという手もあるが、既に英語以外を母語としている人は日本の中学レベルの英文法ですら一生かかっても無理だと思われる)。

*8:料理のレシピは日本の受験英語で習わない単語や言い回しが多いので最低でもTOEICのRで425程度は取れる実力じゃないと難しいのだが、、、。

*9:15-20単語程度が理想。区切りが悪く20単語を超えるものは無理にやらなくてもOK。

*10:この方法ではリーディングにより20単語程度の暗記が必要。20単語程度となると、意味の理解と文章を組み立てる能力が必要。機械的な丸暗記では人間はせいぜい7±2程度の個数しか暗記できず、20単語の暗記となると、『意味の理解』と『使われた単語群の大雑把なうろ覚え』と『文章作成能力』を駆使する必要がある。『意味』と『うろ覚えの単語群』を元に『文章作成能力』により元の文章を再構成するため、元の文章と意味は同じだが異なる文章になることがあり得る。

*11:日本語の場合の極端な例としては、笑っていいとも!という番組のコーナーで、鼻音だけで何て言っているかを当てるコーナーがあり、『んんんん、んんんん、んんんん、んんん、んんんん』で、『タモさん、タモさん、僕にも、メロン、ください』と通じたというようなものがある。

*12:和訳が存在しない英文を聞いて厳密に意味を精査する必要があるので、ニュースレベルの英文法力は必須。単語については辞書を引けばいいので特に問わない。

*13:効率だけを重視する場合、無音部分の少ない日本アニメの北米版を教材とするのがおすすめ。翻訳英語なので自然ではない言い回しも多々含むが、逆に日本人的思考が元となったセリフ回しなので、ストレスなく学習できる。比較的長いセリフでも聞き取って理解できるという状況まで実力アップするための手段という割り切りが重要。英語の映画100時間よりセリフが詰まった日本のアニメ1時間のほうが学習効果が高い。

validation と sanitization

ふと思ったのでメモ。

validation/sanitization 済みであることを示す interface が結構便利。*1

1か所でも validation/sanitization を行う個所があるならオブジェクトとして扱う方向を考えたほうがいいかも。なぜなら validation/sanitization のロジックをカプセル化する場所になるので。

*1:基本的には validation/sanitization 対象が不変かつ対象のデータに閉じて判断可能な場合のみ可能だが、全てを静的に判断できない場合でも静的に判断可能なチェックのみ完了したこと(例えば住所文字列フォーマット準拠とか)を表す interface を用意するのは有用。

robustness と correctness

robustness は要件として検討されるもので、robustness を要件に含めるという文脈でのみ correctness を検討する必要が出てくるんじゃないかと思う。また、基本的には robustness を要件に含めると複雑さや保守コストがかなり増す*1ので、よほど特殊な事情でもない限りは robustness を要件に含めるよりバグのないシンプルな設計を志したほうがいいと思う。*2

結論:予想外*3のエラーの唯一のハンドリング方法は問答無用でシステムを落とすことw*4

*1:非機能要求から機能要求に転化した上に仕様変更が頻繁する可能性もある。また、データのバグを握りつぶして動かしたことにより不正なデータがDBに入り、そのデータがシステム全体のデータに影響を与えた後に発覚した時のマイグレーションは通常はもう手遅れだし、それが課金やシステム内の通貨やポイントだったりした場合はユーザーへの金銭的補償なども発生する可能性がある。実際に、過去においらがその危険性を何度も忠告したのに対策せずに問題を起こした大規模プロジェクトがあった、、、。

*2:結局はユーザーの要求次第なのですがw

*3:どんなにレアな事象でも起こる可能性があるものは予想外じゃないのでエラーではなく例外としてハンドリングすべき。

*4:現実としてはオンメモリでユーザーがデータ編集中の場合とか分散環境の大規模システムの場合などはそうもいかないので、落とす前に編集中データをバックアップするとか、エラー影響範囲を局所化してそこだけ落とす設計とかが必要。特に、不正なデータがそのまま利用されるのだけは確実に阻止することが重要。

The Wise Developers’ Guide to Static Code Analysis featuring FindBugs, Checkstyle, PMD, Coverity and SonarQube

zeroturnaround.com
ちょっと古い記事だけどよくまとまっているのと彼ら自身の経験談でもあるのでメモしておくw

ZeroTurnaround uses SonarQube for our Java projects JRebel and LiveRebel, as we find that it gives us the best combination of usefulness and transparency against the relative complexity of setting it up and solving weird configuration issues.

kotlin における例外について

ふと思ったのでメモ。

  • 例外なくアーキテクチャレベルでの扱いとなり、アーキテクチャ設計書で解説されるべきとか。
  • java で言うところの検査例外は sealed class の戻り値で扱うとか。
  • 検査例外のバケツリレーが発生するような場所はアーキテクチャレベルで実行時例外*1としての扱いを検討するのが良さげとか。*2

preconditions, postconditions and assertions - Be an Idealistic Realist も参照のこと。

*1:kotlin上ならRuntimeExceptionである必要は無いけどjavaとの互換性を考えると実行時例外にしておいたほうが無難だと思われ。

*2:多くの場合、実行時例外の発生可能範囲、ハンドリングを行う境界、具体的なクラスや仕組みなどが定義されると思われ。例えば、エラーが起きてもエラーメッセージだけ表示させてアプリを落とさないようなユーザー要件がある場合に、実行時エラーをスローしてUI側で受けてエラー表示と握りつぶしをする仕組みとか。

kotlin における検査例外的なものについて

ふと思ったのでメモ。

おいらは java では検査例外を結構気に入って使っていたが、kotlin では実行時例外しかないので微妙に困った。しかし、そもそも検査例外に満足していたわけでもない。

基本的にはインタフェースメソッドの仕様はユースケースに近い考え方で、主経路の結果が戻り値、代替経路の結果が例外というような考え方をしている。しかしこれは、様々な側面を考慮したうえで java 言語仕様に合わせた結果こうなったというだけの話で、理想形と言うわけではない。という感じで、いくつか思うところがある:

  • 例外を代替経路の結果としてとらえた場合、常に例外の型だけで代替経路を識別できるわけではない。複数の代替経路で同じ型の値を返したい場合には、代替経路の種類と値の両方の識別が必要となる。kotlin の場合、例外を使わず sealed class で対応し、sealed class の型を経路識別に利用し、経路の網羅性をコンパイラにチェックされるというのが落としどころですかね。
  • 複数の戻り値を得たほうが便利なこともある。純粋関数以外を認めないというのであればそれもいいが、関数は処理の段階的詳細化でも利用される。その際、戻り値が1つだとめんどくさいこともある。例えば x, y, z という int 値を受け取りたい場合、ポインタ渡しのほうがラクチンというようなケースもある。実際はポインタはバグを生みやすいので、kotlin なら destructuring でそれっぽい感じにするというのが落としどころな気はする。val (x, y, z) = hoge() 的な感じで。*1
  • 各経路用のクロージャを渡すという方法も無くはない。副作用のみを期待する場合には実は結構きれいにコーディングできる、、、のだがそれが罠。クロージャ渡しをしたくなる誘惑は主に呼び出し側と呼ばれる側の両方のコードが頭に入っている場合に発生する。例えば、関数Aが関数Bを呼び出し、関数Bの代替経路XとYで個別に処理する場合、代替経路の結果がXであるかYであるかの条件分岐を行ってから処理を行う必要がある。しかし、クロージャを渡してしまえば関数A側は処理を渡してそれでおしまいになる。しかし、クロージャが呼ばれたかどうかの保証は得られないし、クロージャの処理の結果に応じて行うべき処理を後付けしようとしたらクロージャから値を入れるための変数を事前に作るなどの処理が必要となり、コードがかなりカオスになってくる。また、クロージャの処理が実行されるタイミングは関連コードを全てホワイトボックスで同時に把握しない限り判断できないため、クロージャが呼び出されるタイミングが問題になった時に、関連コードすべての coupling が成立してしまう。とかいろいろ問題があるわけだが、コードの実行を時系列で追いづらくなるクロージャは無条件で複雑さを導入するのでそれ以上のメリットが無い場所ではやるべきじゃないと思われ。

とりあえずの結論:

  • 関数を代替経路のあるユースケースに見立てる場合は、例外は使わず sealed class を使い、経路毎に異なる型を割り当てる。*2
  • 関数の戻り値を複数得たい場合や分解して得たい場合は destructuring を利用する。*3
  • 戻り値を判断して対応可能な処理はクロージャ渡しでやらない。

という感じですかね。

*1:hoge()側の戻り値の型をどうするのかはプロジェクトのポリシー次第でしょうね。data class Point3D(val x: Int, val y: Int, val z: Int) のようなクラスを作るのか、Triple<Int, Int, Int> のようにカスタムクラスは作らないで対応するのかなど。可読性や将来的な変更局所性はカスタムクラスのほうが高いと思われる。

*2:when による条件分岐では when を値として利用しない場合も val dummy:Unit = when のように変数に代入して、sealed class の型を網羅していない場合はコンパイルエラーになるようにする方法が結構使える。

*3: val (x, y, z) = hoge() のような感じ。

preconditions, postconditions and assertions

とりあえず思い付きをメモ。

前提として、ゲームやツールアプリ開発にて、バグが発生しても動き続けるよりバグの発生自体を防ぐという方向性を想定。

事前条件と事後条件チェックの面倒な点は、条件が満たせなかった場合に理想的には全部実行時エラーで落とせばいいのだが、性能要件等の充足を阻害する可能性がある点。なので、javaJVM オプションで -ea を付けるか付けないかなどの二択というような方式をアーキテクチャ設計に組み込むと普通に死ねる。

ということで、事前条件と事後条件やアサーションの扱いは、アーキテクチャレベルでガチガチに決め込んでおいたほうがいい気がする。

ちなみに、アサーションについていろいろな考えがあると思うが、以後、プロダクション中では実行されないものとする。

で、何を決め込んでおいたほうがいいのかという話だが、項目は結構多岐に渡るので、実際に採用する場合の例を考えてみる:

  • メソッドとコンストラクタには、事前条件と事後条件が考えられる場合は必ず設定する。
  • 事前条件と事後条件は、条件を満たさないこととバグであることが同一である場合のみを指す。*1
  • 事前条件と事後条件は、基本的にはアサーションとしては扱わず、実行時エラーで落とす方式を採用する。しかし、性能要件充足を阻害する場合はアサーション方式を採用する。
  • バグ時でも強引に実行継続するするような場合はアサーションと例外ハンドリングは併用はせず、バグ発生もユースケースとして通常の例外ハンドリングに含める。*2
  • (メソッドやコンストラクタの呼び出し階層に関して)自身の階層のコード内部で困らないものは条件に含めない。*3

上記のような決め事をした際のメリットとかその他考察:

  • 事前条件と事後条件が自然言語ではなくプログラミング言語で書かれることにより曖昧さがなくなる。
  • 事前条件や事後条件を記述すべきかどうかの判断が不要になる。*4
  • 事前条件と事後条件を常に考えることにより、設計ミスが減る。*5
  • アーキテクチャレベルで決まっているのでコードに統一性が出る。*6

その他考察:

  • 内部コードや信頼できるソースからの入力の場合はアサーションは必要ないという考え方もあるが、これって微妙な気がする。なぜなら、呼び出し側のコードがわからなければその判断できないはずであって、その判断ができるということは、呼び出し側のコードとの coupling を意味するので。*7

という感じで、とりあえずメモしてみたw

*1:例外処理や条件分岐などは含まれない。それらは通常のユースケースとして扱う。

*2:二重管理による変更管理コスト増と変更管理失敗時のリスクがあるため。

*3:例えば userName という String 型のデータや age という Int 型のデータが引数にある際に、UserName や Age クラスとしてバリデーション済みが保証されたインスタンスを扱うのが理想だが、現実的にはそこまでやることは少ない。そのような場合、ユーザー入力やファイルや外部システムから受け取るような場合は受け取る処理自身の責務としてバリデーション(この場合はバグチェックじゃないのでアサーションではない)が入るが、それ以外の場所で呼び出しがあるたびにバリデーションしていたらきりがない。っていうか、そこまでやるなら普通にクラス化すべき。クラス化しない場合は、バリデーションされてないと階層内のコード断片の視点で自身の使命を果たせなくなる場合は事前条件や事後条件を入れないようにする。自身の使命が果たせない場合の例としては、Int を受け取りそれで数字を割るような場合は非0の事前条件を入れるとかは必要。自身の使命が果たせる例としては、アプリとして年齢が10-100歳という前提の時に、10年後の年齢を計算するコードがあった場合、そのコード自身は10-100歳という範囲を知る必要が無いし計算にも影響が無いので、事前条件を設定する必要が無い。ちなみに、『影響が無いから便器的に無視するのであって本来はチェックしたほうがいいんだよね?』という問いにはNO。これは常に無視するのが理想。なぜなら、そのような意味的(semantic)な関連性を考慮していたら、それらのコードは意味的に関連を持ち、結合度が強まってしまう。この syntactic ではないが semantic な coupling というのが実はアプリ開発で最も保守性を低下させるもの。具体的には、10-110歳までの範囲にする仕様変更があった場合に変更箇所どうなるの?コンパイラは教えてくれないよ?コンパイルエラーにもならず実行時エラーにもならないバグになるよ?という話。

*4:絶対に書くというルールなので

*5:特にドメインモデル設計の後半で実コードを書きながら考えられるというのは大きい。

*6:例えば、実行しない、開発時のみ実行(デフォルト)、常に実行、というオプション付きの assert 関数を用意してそれを利用するとか、それを利用した際の例をアーキテクチャ設計書に入れるとか。アーキテクチャ設計書が例ではなく実際のコードを自己参照してしまえば設計書の記述が風化することも無いし(リリースの際に設計書を一字一句全部レビューするという前提が必要だが)。

*7:アサーションを行うということは他のどこかでチェックされているという前提なので、それならそもそも正しいデータであることを保証する interface を用意することによりアサーション自体が必要無くなるはず。例えば、住所の文字列フォーマットをチェックしたいなら、システムへの入り口で Address interface としてチェック済み文字列を用意してしまえば以降のチェックは必要無くなるはず。