失敗から学ぶapi設計 #ccc_h4 #jjug #jjug_ccc jjug ccc 2013 spring

67
Yusuke Yamamoto 失敗から学ぶAPI設計 山本 裕介 @yusuke #ccc_h4

Upload: yusuke-yamamoto

Post on 18-Dec-2014

10.209 views

Category:

Technology


0 download

DESCRIPTION

 

TRANSCRIPT

Page 1: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

失敗から学ぶAPI設計山本 裕介

@yusuke #ccc_h4

Page 2: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

前回までのあらすじ

Page 3: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

前回までのあらすじ

No GGRKS!

使ってもらうためにはどんな汚いことでもする

対象プラットフォームを増やす

外部ライブラリ非依存

Page 4: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

• Twitter APIのJavaラッパ•開発は2007年5月~

Page 5: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4Jは•再利用されているライブラリ

https://wiki.fitbit.com/display/API/API+Java+Client

Page 6: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4Jは•再利用されているライブラリ

http://code.google.com/p/weibo4j/

Page 7: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4Jは•再利用されているライブラリ

http://facebook4j.org

Page 8: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4Jは•イイライブラリ

Page 9: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4Jは•イイライブラリとは

Page 10: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4Jは•イイライブラリとは• 優れたコストパフォーマンス• 機能が豊富• 品質が高い

Page 11: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4Jは•イイライブラリ• 多くのユーザーが使っている• コミュニティが活発• 拡張しやすい• 使いやすい

Page 12: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4Jは•イイライブラリ• 多くのユーザーが使っている• コミュニティが活発• 拡張しやすい• 使いやすい API・設計

Page 13: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

APIとは• Application Programming Interface•何らかの機能を呼び出す口

Page 14: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4JのAPIは• Twitter APIの射影

Page 15: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4JのAPIは• Twitter APIの射影

•現在のところ対象外• キャッシング・永続化• フレームワーク的なこと

Page 16: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4J実装の変遷• バージョン1.0• Twitter APIのXMLのエンドポイント利用• バージョン2.0• OAuthサポート• domオブジェクトを保持しなくなった

Page 17: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4J実装の変遷• バージョン2.1• 非推奨クラス、メソッドをバッサリ• Factoryの導入• バージョン2.2• Basic認証廃止• ライセンスをBSDからASLに変更

Page 18: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4J実装の変遷• バージョン3.0• Twitter API 1.1対応

Page 19: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4Jの開発指針

Page 20: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

シンプルに

Page 21: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

シンプルに

YAGNI

Page 22: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

シンプル・YAGNI•クラス数は極力少なく

Page 23: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

シンプル・YAGNI•クラス数は極力少なく•インターフェースは(なるべく)使わない!

Page 24: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

シンプル・YAGNI•拡張ポイントはなるべく少なく

Page 25: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

(なるべく)immutableに

Page 26: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4Jの拡張ポイント•クラス継承はさせない• 基本finalにして継承を防ぐ• 副作用を生まずに継承を許す設計はすごく難しい

• strategyパターンとか言語道断(一部除く)

Page 27: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

シンプル・YAGNI• Twitter4Jの拡張ポイント• HTTP認証 • 非同期ディスパッチャ• ロガー• HTTPクライアント

Page 28: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

シンプル・YAGNI• Twitter4Jの拡張ポイント• HTTP認証 • 非同期ディスパッチャ• ロガー• HTTPクライアントほとんどのデベロッパは拡張しない

Page 29: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

デザインパターンを適用

Page 30: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

デザインパターンを適用しない

Page 31: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

デザインパターンを適用しないTwitter twitter = new Twitter();

List<Status> statuses = twitter.getPublicTimeline();

for(Status status : statuses){ System.out.println(status.getText());}

多くのプログラマはFactoryとかわからないまずはコンクリートコンストラクタで。

Page 32: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

IDEの補完を活かせるように

Page 33: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

IDEの補完を活かせるように

http://www.youtube.com/watch?v=Nk9CUxEuUww

補完の例

Page 34: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

IDEの補完を活かせるように•なるべく同一パッケージに•一般的過ぎるクラス名にしない

Page 35: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

IDEの補完が活きすぎないように• 使うべきでないクラス名を異様にする• z_T4JInternal******

Page 36: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4Jの成長

Page 37: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

シンプルなTwitter4J

32 KB

Page 38: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

シンプルだったTwitter4J

5.1 MB32 KB

Page 39: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

互換性維持の苦労

Page 40: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

互換性維持の苦労•APIが増える•レスポンススキーマが変わる•ステータスコードが変わる•いつの間にか要素が増えてる•認証方式が変わる•エンドポイントURLが変わる...

Page 41: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4Jの成長• Twitter APIの成長

• Twitter4Jの成長• 膨らむクラス数• 膨らむメソッド数• 膨らむアクセサ数

Page 42: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4Jの成長•至上命題

互換性の維持

Page 43: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

互換性のために大事なこと•クラス名を変えない

Page 44: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

互換性のために大事なこと•メソッド名を変えない

Page 45: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

互換性のために大事なこと•挙動を変えない

Page 46: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

互換性のために大事なこと•直列化形式の互換性を保つ

Page 48: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

互換性のために大事なこと•非互換はコンパイラに検出させる

Page 49: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

互換性を維持できた例•User.java• ユーザー情報

• UserWithStatus.java• ユーザー情報+α

Extended user information with status

User information

Page 50: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

互換性を維持できた例

class User{}

class UserWithStatus extends User{ getFriendsCount();getFollowersCount();}

バージョン1.0

Page 51: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

互換性を維持できた例

class User{ getFriendsCount();getFollowersCount();}/** @deprecated */class UserWithStatus extends User{}

バージョン1.0.4

getterを上位クラスに移動

Page 52: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

互換性を維持できた例

class User{ getFriendsCount();getFollowersCount();}/** @deprecated */class UserWithStatus extends User{}

バージョン1.0.4

UserWithStatusは非推奨、コンパイラが警告

Page 53: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

互換性を維持できた例

class User{ getFriendsCount();getFollowersCount();}/** @deprecated */class UserWithStatus extends User{}

バージョン2.0

UserWithStatusを廃止、コンパイラがエラーを出す

Page 54: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4Jの失敗

Page 55: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

Twitter4Jの失敗•パッケージ分けの失敗• API設計の失敗

Page 56: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

パッケージ分けの失敗•パッケージ分け• twitter4j.*• twitter4j.api.*• twitter4j.auth.*• twitter4j.management.*• twitter4j.internal.*

Page 57: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

パッケージ分けの失敗•パッケージ分けしすぎると• クラスが見つけられない• 特に貧弱なエディタを使っている場合• blogのコード例をコピペしても動かない• import部分の記載がないことが多い• JavaDocの読み方がわからないプログラマは非常に多い

Page 58: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

パッケージ分けの失敗•下手にパッケージ分けすると• 言語使用上仕方なくpublicなクラスが使われてしまうこのパッケージはあのパッケージに対してのみ

公開、とかできるといいが少なくともJavaでは

できない。

Page 59: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

解決策• コードの見通しの問題であればパッケージ分けしない• かわりにソースディレクトリを分ける• クラス可視性はpackage privateで

Page 60: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

mavenでソースディレクトリの分ける設定<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <executions> <execution> <id>add-source</id> <phase>generate-sources</phase> <goals> <goal>add-source</goal> </goals> <configuration> <sources> <source>internal-json</source> <source>internal-async</source> </sources> </configuration> </execution> </executions></plugin>

Page 61: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

API設計の失敗

Twitter twitter = new Twitter();

Page 62: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

API設計の失敗•コンクリートコンストラクタ

•ユーザーにはわかりやすい•が、モックテストしづらい

Twitter twitter = new Twitter();

Page 63: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

API設計の失敗• Twitterをクラスからインターフェースへ• Factoryを導入

• Twitterインターフェースを実装したモックを作れる

Twitter twitter = new TwitterFactory().getInstance();

Page 64: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

API設計の失敗• やはりFactoryパターンは難しい• Singletonを返すstaticメソッドを導入

• あまり知られていない、使われていないTwitter twitter = TwitterFactory.getSingleton();

Page 65: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

参考図書•Effective Java

Page 66: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

参考図書•Practical API Design

Page 67: 失敗から学ぶAPI設計  #ccc_h4 #jjug #jjug_ccc JJUG CCC 2013 Spring

Yusuke Yamamoto

#ccc_h4 #q