例外設計における大罪

37
例外設計 における大罪 和田 卓人 (a.k.a id:t-wada or @t_wada) Jun 27, 2012 @ java-ja 12628日木曜日

Upload: takuto-wada

Post on 17-Nov-2014

44.612 views

Category:

Technology


2 download

DESCRIPTION

例外設計における大罪 Jun 27, 2012 @ java-ja

TRANSCRIPT

Page 1: 例外設計における大罪

例外設計における大罪

和田 卓人 (a.k.a id:t-wada or @t_wada)Jun 27, 2012 @ java-ja

12年6月28日木曜日

Page 2: 例外設計における大罪

自己紹介名前: 和田 卓人 (わだ たくと)

ブログ: http://d.hatena.ne.jp/t-wada

メール: [email protected]

Twitter: http://twitter.com/t_wada

タワーズ・クエスト株式会社 取締役社長

12年6月28日木曜日

Page 3: 例外設計における大罪

よろしくおねがいします

12年6月28日木曜日

Page 4: 例外設計における大罪

例外設計における大罪

12年6月28日木曜日

Page 5: 例外設計における大罪

無視

12年6月28日木曜日

Page 6: 例外設計における大罪

public List<Entity> findByKeyword (String keyword)

throws Exception{ Connection conn = DriverManager.getConnection(...); PreparedStatement stmt = conn.prepareStatement( "SELECT * FROM Movie WHERE title LIKE ?"); stmt.setString(0, keyword); ResultSet rs = stmt.executeQuery(); List<Entity> entities = new ArrayList<Entity>(); while (rs.next()) { // ... } return entities;}

12年6月28日木曜日

Page 7: 例外設計における大罪

•例外処理を行わない言い訳

•コードの流れが追いにくくなる

•納期が迫っている

•エラーが戻ることが無い関数もある

•遊びで書いただけのプログラムだから…

きのこ93: エラーを無視するな

12年6月28日木曜日

Page 8: 例外設計における大罪

きのこ93: エラーを無視するな

•エラーを無視しても何も良いことは無い

•不安定なコード

•セキュリティ上問題のあるコード

•貧弱な構造とインターフェイス

•どうする?

•戻り値を使う

•例外を使う12年6月28日木曜日

Page 9: 例外設計における大罪

隠蔽

12年6月28日木曜日

Page 10: 例外設計における大罪

“try-catchブロックをコードベースに大量に入れれば、「例外が発生しても絶対に止まらない」というアプリケーションを作ることが可能なはずです。ただ、これは、もう死んでいる人の体を釘か何かで固定し、無理矢理立った状態にしているようなものですが・・・。”

きのこ27: 死ぬはずのプログラムを無理に生かしておいてはいけない

12年6月28日木曜日

Page 11: 例外設計における大罪

}  finally  {                if  (rs  !=  null)  {                                try  {                                                rs.close();                                }  catch  (SQLException  e)  {                                                log.warn(e.getMessage(),  e);                                }                }                if  (stmt  !=  null)  {                                try  {                                                stmt.close();                                }  catch  (SQLException  e)  {                                                log.warn(e.getMessage(),  e);                                }                }                if  (con  !=  null)  {                                try  {                                                con.close();                                }  catch  (SQLException  e)  {                                                log.warn(e.getMessage(),  e);                                }                }}

遠い記憶

最近の Java に関しては try-with-resources で検索すべし12年6月28日木曜日

Page 12: 例外設計における大罪

乱用

12年6月28日木曜日

Page 13: 例外設計における大罪

public int sum(List<Integer> toSum) {Iterator<Integer> iter = toSum.iterator();int sum = 0;try {while(true) {sum += iter.next();

}} catch (NoSuchElementException e) {}return sum;

}

12年6月28日木曜日

Page 14: 例外設計における大罪

•例外は、その名が示す通り、例外的条件に対してのみ使用するべきです。通常の制御フローに対しては、決して使用すべきではありません。

•上手く設計された API は、通常の制御フローに例外を使用することを、クライアントに強制してはなりません。

項目57: 例外的状態にだけ例外を使用する

12年6月28日木曜日

Page 15: 例外設計における大罪

•「すべての例外ハンドラーを除去しても、このプログラムは動作することができるだろうか?」

•答えが「ノー」であれば、例外では無い状況下で例外が使われている

ヒント34: 例外は例外的な問題のみに使用すること

12年6月28日木曜日

Page 16: 例外設計における大罪

過剰防御

12年6月28日木曜日

Page 17: 例外設計における大罪

防御的プログラミングの是非

12年6月28日木曜日

Page 18: 例外設計における大罪

package javaja;

public class Defensive {private UserRepository userRepository;public Defensive(UserRepository userRepository) {

this.userRepository = userRepository;}

public User createUser(String name, int age) {if (name == null) {

throw new NullPointerException("name is null");}if (age < 0) {

throw new IllegalArgumentException("age is negative");}if (name.isEmpty()) {

throw new IllegalArgumentException("name is empty");}User user = this.userRepository.create(name, age);return user;

}}12年6月28日木曜日

Page 19: 例外設計における大罪

package javaja;

public class UserRepository {public User create(String name, int age) {

if (name == null) {throw new NullPointerException("name is null");

}if (age < 0) {

throw new IllegalArgumentException("age is negative");}if (name.isEmpty()) {

throw new IllegalArgumentException("name is empty");}return new User(name, age);

}}

12年6月28日木曜日

Page 20: 例外設計における大罪

答えはあるのか

12年6月28日木曜日

Page 21: 例外設計における大罪

契約による設計

Design by Contract (DbC)

12年6月28日木曜日

Page 22: 例外設計における大罪

BertrandMeyer

12年6月28日木曜日

Page 23: 例外設計における大罪

•あるルーチン(注: メソッドと読み替えても良い)におけるすべての事前条件が呼び出し側によって満足された場合、そのルーチンは作業完了時にすべての事後条件とすべての不変表明を保証する

契約による設計Design by Contract (DbC)

12年6月28日木曜日

Page 24: 例外設計における大罪

契約による設計Design by Contract (DbC)

•冗長性のある検証は実際損傷を与える

•システム全体の視点で見るとき、シンプルさ(simplicity)が重要になる

•複雑さは品質の敵である

•過剰に防御するのではなく、誰の責任なのかをはっきりさせる

12年6月28日木曜日

Page 25: 例外設計における大罪

契約による設計Design by Contract (DbC)

•例外処理とは、予想外の実行時状態に対処するメカニズム

•失敗とは、ルーチンの実行で、契約を満足させられなくなること

12年6月28日木曜日

Page 26: 例外設計における大罪

•ルーチンはリトライ(Retry)か組織的パニック(Organized Panic)のどちらかで例外を処理する

•リトライとはルーチン本体を再び実行すること

•組織的なパニックはルーチンを失敗にして、そのルーチンを呼び出したものに例外を送る

契約による設計Design by Contract (DbC)

12年6月28日木曜日

Page 27: 例外設計における大罪

12年6月28日木曜日

Page 28: 例外設計における大罪

おまけ12年6月28日木曜日

Page 29: 例外設計における大罪

きのこ21: 技術的例外とビジネス例外を明確に区別する

•技術的例外とビジネス例外がある。これらを同じ例外階層構造に入れてはならない

•技術的例外は貫通させてフレームワークに任せる。ビジネス例外は準正常系なので呼び出し側で対処する

12年6月28日木曜日

Page 30: 例外設計における大罪

“「出来てはならぬことを禁じる」のではなく、はじめから「出来ていいことだけを出来るようにする」と考えるのです。”

きのこJ6: 見知らぬ人ともうまくやるには

12年6月28日木曜日

Page 31: 例外設計における大罪

Effective Java 2nd

•回復可能な状態にはチェックされる例外を、プログラミングエラーには実行時例外を使用する

•チェックされる例外を不必要に使用するのを避ける

•標準例外を使用する

•抽象概念に適した例外をスローする12年6月28日木曜日

Page 32: 例外設計における大罪

Effective Java 2nd

•各メソッドがスローするすべての例外を文書化する

•詳細メッセージにエラー記録情報を含める

•エラーアトミック性に努める

•例外を無視しない

12年6月28日木曜日

Page 33: 例外設計における大罪

“チェック例外の代償は、開放/閉鎖原則に違反する点です”

=> 検索すれば良質の議論が読めます

12年6月28日木曜日

Page 34: 例外設計における大罪

まとめ12年6月28日木曜日

Page 35: 例外設計における大罪

まとめ•例外処理/設計における大罪•無視•隠蔽•乱用•過剰防御•「契約による設計」がひとつの答え

12年6月28日木曜日

Page 36: 例外設計における大罪

名著を読もう!

12年6月28日木曜日

Page 37: 例外設計における大罪

ご清聴ありがとうございました

12年6月28日木曜日