SwaggerでREST APIドキュメントを生成する


2016/06/24 追記
www.itmedia.co.jp

今のところまだこの脆弱性の対策版がリリースされていないので注意。


だいぶ昔にJersey(JAX-RS参照実装)についての記事を書いてからずっと気になっていたんですが、せっかくアノテーションを使ってURLとメソッドとの間にヒモ付が出来たのに、このアノテーション情報からJavadoc的なAPIドキュメントを生成する方法は無いものかと思っていました。
追記: いやjerseyでwadlを生成できるけどレスポンスのJSONXMLの構造については何も情報が出ないので・・・)

JAX-RSでは今のところAPIドキュメント生成についてはカバーして無いようですが、最近仕事でREST APIドキュメントを生成出来ないかという話が出てきたので調べてみるとSwaggerというREST APIドキュメント生成フレームワーク?が有るようなので触ってみました。

Swaggerを使ったREST APIドキュメントはこんな感じです

Swagger-UI デモサイト


URLとHttpメソッドの組み合わせで、どのようなパラメータを受け付けるのか、戻ってくるJSONの構造、エラー時のhttpステータスコードといった情報を一覧取得することが可能です。

例: http://petstore.swagger.wordnik.com/#!/pet/getPetById



ちょうどJersey(Jax-RS) + AngularJSの組み合わせでサンプルを作っていたので、こいつをSwaggerによるREST APIドキュメント生成に対応させてみます。
というか、あっけなくREST APIドキュメントが生成されてちょっと感動したので、手順を書いてみます。

JerseyベースのRESTサービスでREST APIドキュメントを生成するためのステップ

以下の環境を前提としています。

  • Java8
  • Tomcat8
  • maven2以降
  • Jerseyを使用したREST APIが既に作成済み

 (ソースについては後日githubへpush予定)

1. pom.xmlの編集(maven使用時)

dependenciesエレメントに下記のdependencyを追加してください。

        <dependency>
            <groupId>com.wordnik</groupId>
            <artifactId>swagger-jersey-jaxrs_2.10</artifactId>
            <version>1.3.0</version>
        </dependency>

2. web.xmlの編集

まずはjerseyのservletについて。
元々のservlet定義は

    <servlet>
        <servlet-name>Example Web Application</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>jp.gr.java_conf.ka_ka_xyz.example.service</param-value>
        </init-param>
        <init-param>
            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Example Web Application</servlet-name>
        <url-pattern>/service/*</url-pattern>
    </servlet-mapping>


ですが、以下のように"com.sun.jersey.config.property.packages"にswaggerのパッケージ名を追加してください。

    <servlet>
        <servlet-name>Example Web Application</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>jp.gr.java_conf.ka_ka_xyz.example.service;com.wordnik.swagger.jersey.listing</param-value>
        </init-param>
        <init-param>
            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Example Web Application</servlet-name>
        <url-pattern>/service/*</url-pattern>
    </servlet-mapping>


また、以下のservlet定義を追加してください。

    <servlet>
      <servlet-name>JerseyJaxrsConfig</servlet-name>
      <servlet-class>com.wordnik.swagger.jersey.config.JerseyJaxrsConfig</servlet-class>
      <init-param>
        <param-name>api.version</param-name>
        <param-value>1.0.0</param-value>
      </init-param>
      <init-param>
        <param-name>swagger.api.basepath</param-name>
        <param-value>http://localhost:8080/AngularjsWithSwagger/service</param-value>
      </init-param>
      <load-on-startup>2</load-on-startup>
    </servlet>


初期パラメータ"api.version"はREST APIバージョン、 "swagger.api.basepath"はREST APIのURLを指定します。

3. リソースクラスの編集

もともと、クラス自体に@Pathアノテーションが付いていましたが

@Path("/employee")
public class EmployeeService {
    //

このようにjavax.ws.rs.Pathとcom.wordnik.swagger.annotations.Apiアノテーションを追加してください。

@Path("/employee")
@Produces(MediaType.APPLICATION_JSON)
@Api(value = "/employee", description = "社員に関するサービス")
public class EmployeeService {
    //略

また、もともとこんな感じでメソッドとURL・戻り値のMediaTypeを対応付けていましたが、

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/all")
    public List<Employee> getEmployees(){
    //略

以下のようにcom.wordnik.swagger.annotations.ApiOperation, com.wordnik.swagger.annotations.ApiResponses, com.wordnik.swagger.annotations.ApiResponseアノテーションを使ってREST APIドキュメント用の説明を書いてください。

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/all")
    @ApiOperation(value = "全ての社員情報を取得", notes = "条件指定せず、すべての社員情報を取得する", response = Employee.class)
    @ApiResponses(value = {
      @ApiResponse(code = 500, message = "サーバー内部エラー") 
    })
    public List<Employee> getEmployees(){

4. モデルクラスの編集

もともとこんな感じでJax-RBアノテーションを使用してJSONとの対応付けていましたが

@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee implements Serializable{
    
    /**内部的に使用されるUUID*/
    @XmlAttribute
    private String id;
    /**一意な社員コード*/
    @XmlAttribute
    private String employeeCode;

以下のように、com.wordnik.swagger.annotations.ApiModel、 com.wordnik.swagger.annotations.ApiModelPropertyアノテーションを使ってREST APIドキュメント用の説明を書いてください。

@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
@ApiModel(value = "社員情報")
public class Employee implements Serializable{
    private static final long serialVersionUID = -7816174850279421158L;
    
    /**内部的に使用されるUUID*/
    @XmlAttribute
    @ApiModelProperty(value = "内部的に使用されるUUID", required=true)
    private String id;
    /**一意な社員コード*/
    @XmlAttribute
    @ApiModelProperty(value = "社員コード", required=true)
    private String employeeCode;

5. api-doc JSON生成を確認

さて、mavenでビルドしてwarファイル(AngularjsWithSwagger.war)をデプロイします。

http://localhost:8080/AngularjsWithSwagger/service/api-docs

へアクセスすると、

{"apiVersion":"1.0.0","swaggerVersion":"1.2","apis":[{"path":"/employee","description":"社員に関するサービス"}]}

のようなJSONを取得できるはずです。これはweb.xmlおよびリソースクラスのアノテーションで記述したREST API全体についての情報がJSON形式で出力されているものです。

また、

http://localhost:8080/AngularjsWithSwagger/service/api-docs/employee

へアクセスすると("employee"はリソースクラスのcom.wordnik.swagger.annotations.Apiアノテーションで指定されたパス)、swaggerが生成したREST APIに関する説明を示すJSON文字列が出力されるはずです。

6. swagger-uiでドキュメントを見る

さて、取得したJSONをユーザーフレンドリーな形で表示するには、swagger-uiを使用する必要があります。

とりあえず

GitHub - swagger-api/swagger-ui: Swagger UI is a dependency-free collection of HTML, Javascript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.

からzipをダウンロードし、binフォルダの内容を適当な名前(swagger-ui)に変更し、webappsフォルダへ配置します。

その後

http://localhost:8080/swagger-ui/?url=http://localhost:8080/AngularjsWithSwagger/service/api-docs

へアクセスすると、

f:id:ka-ka_xyz:20141030003117p:plain

と、REST APIドキュメントが表示されます。各メソッドをクリックすると

f:id:ka-ka_xyz:20141030003145p:plain

のように、JSON構造やパラメータ、レスポンスコード情報等が表示されます。



追伸(業務連絡)東宝怪獣的なサーバー名に心当たりのある人は「これ書いたのはアイツか」とか思わずに素知らぬ顔でスルーしてください。

「金持ちは税率70%でもいいVSみんな10%課税がいい」感想

金持ちは税率70%でもいいVSみんな10%課税がいい: 1時間でわかる格差社会の増税論

金持ちは税率70%でもいいVSみんな10%課税がいい: 1時間でわかる格差社会の増税論

金持ちからもっと税金をとるべきか。

この、現代社会のきわめて重要なテーマについて、
4人の知性が激論を交わします。

クルーグマンとパパンドレウは、金持ち増税に賛成。

・スーパーリッチの税負担をちょっと増やしても経済に悪影響はない。
・平等な社会のほうがいろいろな面で望ましい、

というのがその根拠です。

一方のギングリッチとラッファーは、金持ち増税に反対。

・がんばって成功した人からむしりとってそうでない人に渡すような社会でいいのか。
増税しても、金持ちは賢い弁護士をやとって抜け道を探し出す。
増税の前に、政府を改革して効率化するべきだ、

というのがその根拠です。

税の問題は、つきつめれば、誰からとって誰に与えるか、という問題になります。
その問題を考えるときの主要な論点を網羅した本です。

この手のディベート本は初めて読むけど、「朝まで生テレビ」的なgdgdに陥らずに議論できてるってだけでもう羨望モンですよ。
で、争点な累進課税について。日本でも所得税最高税率は80年代中盤まで70%以上( 所得税 - Wikipedia )だったんですが、この辺は米国も同様に昔は結構最高税率が高かったという話が出てて意外。まあ、そういう制度が妥当かどうかという点はともかくとして、それでも社会は回る(むしろ日本でも米国でも結構景気がいい時代には最高税率が高い)という所は面白い。


あと、この本の笑いどころ。元米下院議長のニュート・ギングリッチ氏が「累進課税なんか止めて公平に課税しようぜ派」として熱弁をふるっているのですが。

[ギングリッチ] (前略。「金持ちからもっと税金を取るべきか?」という質問に対して)ビル・ゲイツの財産を没収すべきなのか?結局のところ、何十億も持っている必要は無い訳で。
 
[グリーン(インタビュアー)] そんな簡単な話ですか?
 
[ギングリッチ] 政府がやるのはそういうことですよ。政府は奪うんです。政府は権力であって、慈善団体では有りません。「僕等に手を貸してくれたらうれしいんだけど」なんて政府は言わないわけです。(後略)

すげーよ。元下院議長で大統領選候補にもなったガチな政治家が、

「政府は奪うんです。」

発言ですよ。もしホントにそう思ってるんなら政治家になって泥棒の片棒を担ぐなんてことやらずに「アメリカリバタリアン革命軍」でも作ってゲリラ活動するべきでは?
(まあ、「行政府と立法府は違う。行政府の専横を抑えるのが立法府なのだ」って理屈かもしれないけど、「奪った」お金の分配方法について議論する場の元責任者がそういうこと言ってもな~)

森岡浩之「突変」感想(ネタバレ有り)

突変 (徳間文庫)

突変 (徳間文庫)

関東某県酒河市一帯がいきなり異世界に転移(突変)。ここ裏地球は、危険な異源生物(チェンジリング)が蔓延る世界。妻の末期癌を宣告されたばかりの町内会長、家事代行会社の女性スタッフ、独身スーパー店長、ニートのオタク青年、夫と生き別れた子連れパート主婦。それぞれの事情を抱えた彼らはいかにこの事態に対処していくのか。異様な設定ながら地に足のついた描写が真に迫る、特異災害(パニツク)SF超大作!

異世界にいきなり放り込まれる系SF。


ある時期から、ある程度の広さの地域が消失し、かわりに現在の地球とは全く異なる凶暴な生態系へ置き換えられるという「突変」現象が発生するようになった世界。元々存在していた場所は、その全く異質な生態系を持つもう一つの(おそらく平行世界上の)地球に存在する同じ地域と置き換えられてしまうと推定されています。
S・キング「霧」( スケルトン・クルー〈2〉神々のワード・プロセッサ (扶桑社ミステリー) 収録)あたりとシチュエーションは似てるかもしれない。


過去に人口密集地(関西圏中核部とか)がまるごと「突変」してしまったこともあり、それなりの規模の人口・産業基盤が「突変」先の地球上に存在し、社会を維持している可能性はあります。ただし、その平行世界と連絡を取る方法は全く存在していないため、「突変」先の世界でどのような社会が築かれているのかは全くわかっていません。

この「突変」現象は現実世界でいうところの巨大地震のように、稀にしか発生しないものの防ぎようの無い天災として認識されています。なので市役所レベルで外の地域と切り離されることを想定した非常食糧が備蓄されていたり、「突変」先の生物へ対応するため軽火器を扱う「防除団」が組織されていたりといった行政レベルでの対策は取られていますが、かといって今日明日にも自分たちが「突変」してしまうという切迫感はあんまり有りません。

で、どうという事もない平凡な郊外ベッドタウンでの平凡な日常の中で「突変」現象が発生し、否応なく異世界でのサバイバルが始まることに・・・・・・

面白いのでオススメだけど、ちょっと気になる点もあるので以下ネタバレ。

続きを読む

javaScriptとノーブレークスペースについてあれこれ

ノーブレークスペースについて

ノーブレークスペースってなんぞやというと、Web系の人にとってはお馴染みなはずの実体参照"&nbsp;"で表示される空白文字です。Unicode符号は0x00A0。
通常の半角スペース文字は0x0020なので、見た目は同じ空白文字でも実態は違う文字です。

細かいことはwikipedia参照。
ノーブレークスペース - Wikipedia

何でこんな事を書いてるかというと

<!DOCTYPE html>
  <html>
    <head>
      <meta charset="UTF-8">
    <head>
  <body>
    <div id="example">This&nbsp;is&nbsp;a&nbsp;pen</div>
  </body>
</html>

というhtmlに対して

var acutualText = document.getElementById("example").textContent;
var expectedText = "This is a pen";
assertEquals(acutualText, expectedText);

みたいなテストを書いてて通らなかった事がきっかけ。

見分け付ける方法

取り敢えず、文字列をユニコード符号で見てみましょう。

こんな感じのhtmlをブラウザで表示し

<!DOCTYPE html>
  <html>
    <head>
      <meta charset="UTF-8">
    <head>
  <body>
    <div id="whitespace">This is a pen</div>
    <div id="nbsp">This&nbsp;is&nbsp;a&nbsp;pen</div>
  </body>
</html>

コンソールから以下を実行

String.prototype.toCharCode = function (){
    var rtn = "";
    var myself = this;
    this.split("").forEach(function(s, i){
        var c = myself.charCodeAt(i).toString(16).toUpperCase();
        rtn += " U+" + (c.length === 2 ? "00" + c : c);
    })
    return rtn.length > 0 ? rtn.substr(1):"";
}

//ホワイトスペース区切り文字列
var whitespace = document.getElementById("whitespace").textContent;
//ノーブレークスペース区切り文字列
var nbsp = document.getElementById("nbsp").textContent;

console.log("ホワイトスペース(U+0020)区切り:   " + whitespace.toCharCode());
console.log("ノーブレークスペース(U+00A0)区切り: " + nbsp.toCharCode());

結果はこんな感じ

ホワイトスペース(U+0020)区切り: U+0054 U+0068 U+0069 U+0073 U+0020 U+0069 U+0073 U+0020 U+0061 U+0020 U+0070 U+0065 U+006E

ノーブレークスペース(U+00A0)区切り: U+0054 U+0068 U+0069 U+0073 U+00A0 U+0069 U+0073 U+00A0 U+0061 U+00A0 U+0070 U+0065 U+006E

太字強調した部分は区切り文字ですが、ちゃんとノーブレークスペース文字が"U+00A0"として取得出来ている事が分かります。

空白文字の違いなんかどうでもいいからさっくり文字列比較したい

正規表現の"\s"はホワイトスペース文字(U+0020)だけに限らず空白文字全般にマッチするので、String.prototype.replace()を使ってホワイトスペースへ置換するのが一番手っ取り早いかと。

例:

//ホワイトスペース区切り文字列
var whitespace = document.getElementById("whitespace").textContent;
//ノーブレークスペース区切り文字列
var nbsp = document.getElementById("nbsp").textContent;

var nbsp_replaced = nbsp.replace(/\s/g, " ");

console.log("ホワイトスペース(U+0020)区切り:   " + whitespace.toCharCode());
console.log("ノーブレークスペース(U+00A0)区切り: " + nbsp.toCharCode());
console.log("置換後: " + nbsp_replaced.toCharCode());
console.log("置換後に一致するか? " + (whitespace === nbsp_replaced));

結果はこんな感じ

ホワイトスペース(U+0020)区切り: U+0054 U+0068 U+0069 U+0073 U+0020 U+0069 U+0073 U+0020 U+0061 U+0020 U+0070 U+0065 U+006E

ノーブレークスペース(U+00A0)区切り: U+0054 U+0068 U+0069 U+0073 U+00A0 U+0069 U+0073 U+00A0 U+0061 U+00A0 U+0070 U+0065 U+006E

置換後: U+0054 U+0068 U+0069 U+0073 U+0020 U+0069 U+0073 U+0020 U+0061 U+0020 U+0070 U+0065 U+006E

置換後に一致するか? true

ノーブレークスペース(U+00A0)が全てホワイトスペース(U+0020)へ置き換えられ、文字列比較も一致することが確認できました・・・と、ここまではChrome上での話。

ブラウザごとのノーブレークスペースの扱い

jsでテキストノードの値を取得するには、大抵textContentかinnerTextを使うかと思いますが、各ブラウザごとにノーブレークスペースの扱いがどうか見てみましょう。

Chrome Firefox IE11
textContent 0x00A0 0x00A0 0x00A0
innerText 0x00A0 (innerTextは未サポート) 0x0020


IE11ではinnerTextでテキストを取得した時に、ノーブレークスペース("0x00A0")がホワイトスペース("0x0020")として取得されます。textContentがサポートされたのはIE9以降(参照
Node.textContent - Web API インターフェイス | MDN
)となるため、textContentが使えないレガシーIEでノーブレークスペースをノーブレークスペースとして扱うのは手間がかかりそう(innerHTMLで文字列"&nbsp;"として取るか)。

「エリア51 世界でもっとも有名な秘密基地の真実」感想

エリア51 世界でもっとも有名な秘密基地の真実 (ヒストリカル・スタディーズ)

エリア51 世界でもっとも有名な秘密基地の真実 (ヒストリカル・スタディーズ)

「NYタイムズ・ベストセラー・リスト」に11週連続でランクインした全米ベストセラーが日本上陸! エリア51の知られざる数々の事実、核や人体実験などアメリカ軍事史の闇に迫る渾身のノンフィクション! ◆「エリア51」はUFO墜落・宇宙人の遺体回収で知られる「ロズウェル事件」の舞台として世界的に有名だが、実際はネヴァダ州の砂漠地帯にある米最高機密の軍事施設である。衛星写真でも隠せないほど広大な基地にもかかわらず、いまも当局は存在を伏せている。 ◆ジャーナリストの著者は、ふとしたきっかけからエリア51で働いていたという人物と知りあい、取材を開始。以後、基地に勤務していた20人近い関係者、プロジェクトに関わった50人以上の科学者、基地近郊の30人を越える居住者などからの証言を得て全容解明に挑戦。その結果、冷戦下の軍事秘史が明らかになった。 ◆貴重なモノクロ写真を約60点収録

学研「ムー」矢追純一UFOスペシャル方面で常に注目を浴びてきた、世界で一番有名な(でも具体的に何をやってるのかさっぱり見えてこない)秘密基地「エリア51」についてのノンフィクション。

まあ、第二次大戦後のドイツから(倫理的にヤバい研究してた人を含め)科学者・技術者をかき集めてきた「ペーパークリップ」作戦、秘密核実験、U-2偵察機の開発、ソ連上空偵察飛行作戦、A-12オックスカート偵察機SR-71ブラックバードのCIA版)開発、偵察機開発を巡る空軍とCIAとの綱引き、核戦争を想定した極秘生体実験、熱核推進ロケット開発、ロズウェル事件の真相等等・・・エリア51とは直接関係無い話も入ってますが、冷戦の「闇」の部分を関係者の豊富な証言を元に再構成してみたという感じの本です。

ただまあ引っかかるのはやはり"ロズウェル事件の真相"(と著者が主張している)話でして。
ソ連ホルテン兄弟の設計にヒントを得て開発した超絶技術の飛行機(空中静止可能で、アメリカ本土まで飛べるほど航続距離が長い。ホルテン兄弟ってそんな超絶技術持ってたっけ?)に生体改造されたパイロットを載せてネバダくんだりまで飛ばしたが結局は墜落し、エリア51に収容されたって話なんですがね・・・著者は「アメリカとしては米本土にソ連機の侵入を許したと認める事が出来なかったし、そもそも自分たちも相当胡散臭いことをしていたから藪蛇にならないように口をつぐんだのだ」と言ってますが、どうにもこうにも、不合理な点を全てソ連スターリンに押し付けただけという感じがします。
普通に考えれば、当時の技術水準を大幅に凌駕しているような貴重な機体を、わざわざ米本土まで飛ばして墜落させたりとかしたらソ連側では政治的大事件になっていたでしょう。それに、後の「スターリン批判」の流れで格好のネタになったはずです。著者的には「いや墜落したことも含めて高度な心理作戦なんだよ!」と主張してますが・・・キバヤシさん乙です。
また、空中で自由に静止出来て、かつソ連領から米本土ネバダまで飛べるような機体を(研究用の一品物であっても)開発できるような技術力があれば、後の実用VTOL機Yak-38フォージャーがなんであんな残念な出来にしかなってないのかとか、合理的に考えると突っ込みどころ満載です。

まあ、"ロズウェル事件の真相"としてセンセーショナルな話を盛り込んでおけば売上的な面で有利だとは思いますが、著者のノンフィクション作家としての誠実さにはかなり疑問を感じます。ほんとうに、他の部分とは違ってこの箇所だけは、その時点での、あるいは現在の技術的・政治的動向とのつながりが全く無いんですよね。


逆にこの点さえ目をつぶれば、当事者の証言による冷戦の裏面史という内容は素晴らしいんですが・・・でも何処まで信用できるのかなあ。
どう考えてもおかしな話を混ぜ込むこと自体が著者による「この本に書かれていることは全て疑え」というメッセージなのだという読み方も可能とは思いますが、その手の陰謀論まっしぐらな読み方はあんまり好きじゃない。

遠藤周作「ブラック大名家に勤めてるんだが、もう俺は限界かもしれない」………じゃなくて「反逆」感想

反逆(上) (講談社文庫)

反逆(上) (講談社文庫)

1度でもいい。上さまの……あの顔に……怯えの影を見たい――己れの力に寸分の疑いをもたぬ信長の自信、神をも畏れぬ信長への憎しみ、恐れ、コンプレックス、嫉妬、そして強い執着……村重、光秀、秀吉の心に揺らめく反逆の光を、克明に追う。強き者に翻弄される弱き者たちの論理と心理を描ききった歴史大作。

反逆(下) (講談社文庫)

反逆(下) (講談社文庫)

なんたる上さまの冷酷――命乞いをする幼な子の首を刎ねた信長、秀吉と光秀、2人の心理的競い合いを楽しむ信長。信長を討つことは天の道!光秀は長い間心に沈澱していた反逆の囁きから解き放たれた……。戦いの果てにみた人間の弱さ、悲哀、寂しさを、そして生き残った村重、右近らの落魄の人生を描く。

いやー、面白い面白い。荒木村重明智光秀松永久秀といった一癖も二癖もある織田家家臣が、相互不信と嫉妬、信長への愛憎、「毛利なら、毛利ならきっと何とかしてくれるはず!」という希望的観測、そして何より信長から「使い捨てされる」ことの恐怖に振り回されて反逆にへと至る心理描写が素晴らしい。
また、反逆に至らないまでも腹に一物ある豊臣秀吉や、裏表無くまっすぐ生きようとしても周囲の事情により色々と抱え込んでしまう高山右近、あるいは歴史に名を残すこと無く消えていった人々の悲壮な思い等の描写についても、中々面白く描かれています。

で、上で書いた"「使い捨てされる」ことの恐怖"なんですが、この辺は

信長と消えた家臣たち―失脚・粛清・謀反 (中公新書)

信長と消えた家臣たち―失脚・粛清・謀反 (中公新書)

でも、反乱を誘発した要素の一つではないかとされており、フィクションの"味付け"として読み流すには勿体無い視点だと思います。

で、人材使い捨てといえば昨今のブラック企業問題ですが、いやほんとに当時の人から見たら「ブラック大名家」だったんじゃないですかね織田家って。まあ、他の勢力が今日的な意味で「ホワイト」だったかって言うとかなり微妙だと思いますが。

「よーく考えよ~実験ノートは大事だよー」ってミリカンさんが言ってた

一連の研究不正事件で参照されることの多い「背信の科学者たち」ですが、復刊が決定したようです。

背信の科学者たち 論文捏造はなぜ繰り返されるのか?

背信の科学者たち 論文捏造はなぜ繰り返されるのか?


「背信の科学者たち」は理系研究でのデータ捏造・恣意的なデータ操作・研究不正についてまとめた古典であり、是非抑えておくべき本ですが、書かれたのが今から30年以上前(1982年)ということで、内容が古くなっている部分がありました。


例えば、今手元にある化学同人から刊行されたハードカバー版では、ミリカンの油滴実験について恣意的なデータ操作による不正が行われていたと書かれています。しかし、最近は恣意的なデータ操作は行われてなかった説の方が有力なようです。

恣意的なデータ操作は行われてなかった説の大本は、David Goodstein 「In Defense of Robert Andrews Millikan」のようです。取り敢えず、「背信の科学者」内でのミリカンの油滴実験についての記述と、"In Defense of Robert Andrews Millikan"の概略をまとめます。

「ミリカンの油滴実験」について

さて、まずは疑惑の対象となっている「ミリカンの油滴実験」について。といっても自分は学部時代は化学系だったので、学生実験などで油滴実験を実際にやった経験はありません。あくまで概略程度で。

実験の目的は、「電子1つあたりの電荷量(電気素量)」を求めることです。そのための実験システムとして、まず霧吹きで細かな油のしずく(油滴)を作ってやります。それらの油滴は、重力に引かれて落ちていきますが、一方で浮力や空気抵抗(空気の粘り気により発生)によって、落下速度はかなりゆっくり目になります。
さて、それらの油滴のいくつかは空気中から電子を取り込んだりして帯電します(X線を当てて強制的に帯電させるような実験方法もある模様)。通常、帯電していようが無かろうが、落下速度に影響はありません。しかし、油滴が電界(電荷が引っ張られる場)の中にいる場合にはどうなるでしょうか?重力。浮力、空気抵抗以外に、油滴に含まれる電荷が電界で引っ張られます。例えば+極が上に来るような電界を作ってやれば、マイナス電荷を持つ油滴は上に引っ張られることになり、落下速度が電界の強さに依存して減少します。
で、電界の強さを変えた時の、油滴の落下速度差を観測してやれば、油滴に含まれる電荷の総量を求めることが出来ます。詳細はWikipedia参照。

ミリカンの油滴実験 - Wikipedia

油滴の中に含まれる電荷が電子一個分に成ることはまず無く、複数の電子による電荷を含んでいると予想されます。つまり、油滴に含まれる電荷は、電子の持つ電荷の整数倍になるはずです。そこで、油滴実験のデータを解析することで、油滴の持つ電荷が「ある数」の整数倍であれば、その数が「電子一個あたりの電荷」(電気素量)となるはずです。

実際に観測される値や。電気素量の検証方法については、下記テキストで詳しく説明されています。

4011 電子の電荷(電気素量e)の測定(ミリカンの油滴実験)


ミリカンは1910年にこの実験結果を発表し、「電子一個あたりの電荷」の測定結果を発表しました。

ミリカンへの疑惑

この実験の解釈について異議を唱えたのが、フェリックス・エーレンハフトです。
1910年の油滴実験論文データにはある程度のバラつきがありました。ミリカンはそれを実験誤差と解釈していましたが、エーレンハフトは『通常の電子より少ない電荷を持つ「副電子」の存在を示している』と解釈し、ミリカンへの異議を唱えました。

この異議に答え、ミリカンは1913年に再度、よりバラつきの少ないな結果を盛り込んだ油滴実験論文を公表しました。この論文中でミリカンは「これは選ばれた油滴群ではなく、60日間にわたり連続して行われた実験の全ての油滴についての結果である」と、まあ平たく言うと良いデータだけを恣意的にチョイスした訳では無いと述べています。この"正確な"測定データによりエーレンハフトが提唱した「副電子」の存在は否定されます。エーレンハフトは独自に電気素量測定実験を継続しますが、ミリカンのようなばらつきの少ないデータを得ることが出来ませんでした。
その後ミリカンはこの実験によりノーベル物理学賞(「電気素量、光電効果に関する研究」)を受賞し、一方エーレンハフトは幻滅の余りか精神病に陥るという結末を迎えてしまいました。
で、ここからが油滴実験への疑惑なんですが、ハーバード大の歴史学者ジェラルド・ホルトンによると、ミリカンの実験ノートには「きれいだ。これを必ず発表しよう」のような私的注釈が付されており、1913年の論文では恣意的に「きれいな」データのみが選択されていた(つまり、ミリカン説に当てはまるデータだけを選択して公表していた)とのことです。

ミリカンは偽りが明らかになることを案ずる必要はなかった。ホルトンはその理由を次のように書いている。
「ノートは私的なものであった。……だから彼はデータを自由に選び……電荷理論と特定の実験によってデータを導き出した。それを彼はすでに最初の重要な論文の中でも行っていた。そしてその後、彼は発表データには星印を付けないことを覚えたのだ」

(「背信の科学者たち」p35より)

要は、観測結果から自分の理論に合わない不都合な部分を切り捨てるような、恣意的なデータ操作で論争に勝利したという疑惑です。「背信の科学者たち」では、このようなノーベル賞級のエポックメーキングな研究ですら研究不正が存在し、しかも結果オーライで見過ごされていたという実例として、ミリカンの事例が取り上げられていた訳です。

ちなみに、ミリカンの実験ノートスキャン画像がカルテクにより公開されてます。

Robert A. Millikan Oil Drop Experiment Notebooks, Notebook One - CaltechLabNotes

Robert A. Millikan Oil Drop Experiment Notebooks, Notebook Two - CaltechLabNotes

結果についてのコメントっぽいことがあちこちに書かれてますが、ミミズの這ったような筆記体で読みにくい。(あと、内容を引用する場合にはカルテクに許可取れと書かれているのでとりあえずリンクのみ)
実験結果は表形式でまとめられており、"G"の欄が電圧をかけない状態、"F"の欄が電圧がかかった状態である油滴が一定距離落下するのにかかった時間とのこと。

ミリカンへの弁護(In Defense of Robert Andrews Millikan)

さて、「ミリカンの油滴実験は恣意的データ操作」説に対する反論について。

In Defense of Robert Andrews Millikan

によると、ミリカンの実験ノートを精査したところ、確かに実験結果についての予断を持ったコメントが有ったものの、恣意的なデータ操作は行われて居なかったとのことです。
1913年のミリカンの論文では「60日間にわたり連続して行われた実験」であると述べられていますが、実際に実験ノートと突き合わせを行い、1912年2月13日から4月16日までの63日間のデータが使用されていることが確認できたとのことです。また、この期間に計測されたデータの幾つかが論文から除外されて居ることは確かであるものの、それらのデータを考慮に入れたとしても、論文の結論にはほぼ影響は無いとしています。
また、この63日間で誤差が少なかった原因として、気候条件が安定していたからではないかと述べられています。上で書いたとおり、油滴にかかる力として浮力や空気抵抗がありますが、これらは温度や湿度、気圧といったパラメーターの影響を受けます。なので、気候条件が不安定な場合、誤差が積み重なる可能性があり、逆に安定していれば誤差が減少すると。

しかしまあ、この反論についても鵜呑みにするのではなく検証していきたいところでは有りますが、実験ノートを解読する難易度が高すぎる・・・

実験ノートは大事だよー

何時、どんな実験を、どのように行い、どんな結果が得られたのかを改ざん困難な形で残してあれば、不正研究疑惑がかけられても弁護してくれる人は居るってことで。

実験ノートは超重要ってことを草葉の陰でミリカンさんも言ってる気がする(イタコ的に)。