疑似コード(pseudocode)について

ふと思ったのでメモ。

疑似コードをプロジェクトで正式に採用したことはないんだけど、要求開発のツールとしてドメインモデリングを採用する際に、インタフェース設計の後に一段階入れても面白いかも。予想されるメリットは以下:

  • インタフェース設計のみより多くのフィードバックが期待でき、コストもそれほど大きくない。*1
  • リリース後の保守コストがゼロ。*2
  • 工数の見積もりが高精度で立てられ、かつ、この活動によって、工数の読みづらい実装時の手戻りを削減できる。*3
  • ソースコードシンタックスエラーを気にして不必要に細かいところまで考えてしまうことが無くなる。
  • 実装時にソースコード上のコメントを考えることや、実装後に後付けすることが無くなる。結果として、実装に準じるようにうまくコメントを書くという本来と逆の思考により不適切なコメントを書くことを避けられる。
  • レビュー時に、実装技術の細かい話の話になったり、レビュー者が実装技術の細かい点につい意識を持って行かれるようなことが無い。*4
  • ダメな案を抱えてしまうリスクの排除。*5

要検討な点:

  • 疑似コードを利用するかどうかの判断が必要になる。*6
  • 書式をある程度一般化する必要がある。*7
  • 複雑だが本質的なロジックの場合、ソースコードを直接書いたほうが厳密かつ分かりやすいよね。そういう場合にどうするか。*8
  • どこまで疑似コードで掘り下げるかの判断基準が必要。*9

*1:インタフェース設計フェーズを拡張するだけで行けると思われ。

*2:リリース時には疑似コードはすべて実際のコードに置き換わっているため。

*3:固定金利と変動金利スワップのようなもので、リスク管理手法としてはかなりおいしいと思われる。

*4:設計レベルのレビュー時にインデントのスタイルとかスペースの入れ方とかfor/while/forEach等のどれを使うべきかとかを話しても意味がない

*5:コーディングまで完了させてしまうと、心理的にそのコードを捨てづらくなる。数行の疑似コードであれば捨てやすい。

*6:setter/getterなどに作っても意味が無いので。しかし、setterにバリデーションがあったらどうなの?とか考えだすと、かなり明確な判断基準がないと運用が難しそう。っていうか、全部疑似コードを書くと決めてしまったほうが早いかもですね。単純なgetterならお決まりの文を1行入れるだけなのでコストはかからんし、後でバリデーションロジックなどが入るかもしれんし。そもそも疑似コードを書くという行為によって『バリデーションいるんじゃね?』的な気付きを得られる可能性が増すという考えもあるよね。

*7:順次・選択・反復系をどう表すかなど。たぶん、いくつかのパターンの例を示しておく程度でもいい気がする。形式化しすぎると本末転倒だし。

*8:例えば、独自サービスのポイント付与ロジックとか、大半はプログラミング言語の syntax で記述したほうがわかりやすいと思われる。

*9:インタフェースからほぼ自明な処理は疑似コードは書かず、そうでないものはすべて機械的に実装に書き換えられるレベルの粒度まで掘り下げてもいいかも。しかし、ドメインモデルのインタフェース直下ではなく派生したルーチンとかクラスが必要になる場合は要検討だけど、直観的にはそこまではやらんほうがいいと思われる。そこまでやったらもう要求設計フェーズじゃないよねwww。ドメインモデル以外については、臨機応変にやるのがたぶん正解。作業者のレベルや経験値やコード資産の流用などによる影響が大きすぎるので。

英語勉強法について

思ったことをとりあえずメモするプレイスホルダー。思い付きやネイティブの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() のような感じ。