とりあえずやってみればいいじゃん

読者です 読者をやめる 読者になる 読者になる

とりあえずやってみればいいじゃん

エンジニア関連のことについてつらつら書くブログ

3/3 Swiftでのエラーハンドリングとエラー耐性についての教訓 #tryswiftconf

try!Swiftのセッションまとめシリーズです。Christopher Rogersさんの「Lessons in Swift Error Handling and Resilience」についての記事になります。

資料

内容

前置き

  • Swiftのエラーに関して
    • ここでのエラー=エラー型ではなくコードの中で誤作動しそうで理想的ではないもの
  • 背景
    • 安定的、正常に動作するコードを求めている
    • 常に意図したことをやってくれるコード
  • 予期しない不具合から復帰してユーザへの影響範囲を最小限にしたい
    • DBからユーザの一部が読めない時、単にクラッシュして諦めることはしなくない
    • ユーザがコントロールできないものはなおさら大事
    • DoS攻撃に陥らないようにしたい
    • カスタマーサポートで「再インストールしてください」は避けたい
      • 信頼失うかも
  • 正しいコードを書く
    • 維持できるコード
    • テスト可能なコードをどう書くか

入力に関して

  • エラーを防ぐためには全ての入力を扱えるようにする
  • 明示的な入力
    • 読み手に目立つ、より明確に伝える
    • 関数の引数になる
    • selfは暗黙的にパスされる
  • 暗黙的な入力
    • 関数にアクセスできるデータ
    • ステート、状態と呼ばれている
    • 状態はグローバルで定義されている
    • 関数はこれらの値に依存している
    • 同じインプットでも変わることがある
    • Pure Functionについてはswift-evoでも議論がされている→これ?

時間的状態に関して

  • ある時間で実行されているコード
  • 部分的に命令形コードの順番によって定義
  • 時間的状態は最も暗示的
  • コードを実行する順番は明示的にできる(コメントを活用するなど)

並列処理に関して

  • 同時並行型プログラミング
    • print文をお互いから隔離して実行する
    • スレッドが異なったパターンで折り混ざる
    • 3つのストリームに分かれた
  • 同時並行なし
  • 何がdoSomethingを興味深くさせているか
  • 負の数以外のものを格納していると想定する
  • 今後のversionで実行できるのか
  • 状態の変更は無計画にやるべきではない

バグの例

  • きせかえ機能
  • 着せ替えテーマはUserDefaultで保存
  • アプデ後初めて実行されるコードにテーマ設定を取り出し新しい形式で保存するコードを追加
  • コードに問題があった
    • アプリ起動時にデフォルトテーマで立ち上げると一つ前のテーマに戻ってしまう
    • サブシステムが移行の前に初期化されてしまった
    • しかしその後の立ち上げ時は初期化うまくいく
    • 曖昧な依存関係に起因
  • 再発防止は?
    • 2者の関係をコンパイル時の型を使って明示する
    • 入力として呼び出すことができなくなる
    • 型のインスタンスを引数として受け取ることによってその型が表す状態を前提条件として定義することができる
    • 状態が発生した時にインスタンスを作って渡せばいいだけの状態に

Swiftのエラー型について

  • Error型とオプショナル型どちらを優先して使うべきか
  • オプショナル型
    • 正しいかどうか、あるかないかを表す
    • 任意の意味
  • エラー型
    • 不正解、正常に処理できなかった
    • 致命的、壊滅的エラーに使われる
    • 壊れたDBにアクセスしようとしている
    • ハッピーパスを書くことに向いている
  • ほとんどのswiftプログラマーはカーソルを後ろに戻したりthrowするのを嫌がる
  • エラーは頻繁に起きないのであまり考えたくない
  • 何をやるかは予め定義づけるべき
  • 逆に考えるとSwiftのエラー型は発生率が低いものに対して使うべき

  • 使えば使うほどパターンが見えてきた

  • これはDBから来る値だな、正常に処理されるはず
    • try文へ
  • 今回の例の場合、Error型を使おうと思ったので密結合がある
  • Error型はErrorハンドリングがその型と密結合している時に最も有用であるとわかった
  • throwするとトラブルシューティングが楽
  • パースできない理由を知るだけではダメ

まとめ

  • 入出力の流れを意識しましょう
  • エラー体制を向上させることができる
  • 有効な診断状況を出せないならオプショナル型に
  • 情報量が多い稀なエラーはError型に

Q&A

  • FatalErrorを使うようなどうしようもない場合は?

    • 個人的には行くスクラメーションマークを使って矯正する場合も
    • プログラマエラーにしたり
    • テストで検知できそうなので単に無視するよりは探っていきたい
  • (Resolveに関する質問)

    • Resolveはサーバレスポンスなど一部使っている
    • 機能性が高いかというとそうでもなさそう

その他このトークに関する情報源

togetter

Lessons in Swift Error Handling and Resilience #tryswiftconf - Togetterまとめ