運、 緯度、 レモン ? Indeed の低レイテンシなデータセンターの見つけ方

Indeed は速さを好みます。

既に発表された研究 ( これこれ ) のように、私たちが内部で持つ数値データも、速さの効能を立証しています。

速いサイトは、イライラも無駄な時間も少なく、求職者は目的を果たしやすくなる―これには納得がいきますよね。

けれど、アプリケーションの処理時間はこの話の一部でしかなく、多くの場合、最も重要な遅れではありません。

ブラウザからリクエストを取得し、データを再度返すこと、つまりネットワーク遅延が時間を食う最大の原因です。

ネットワーク遅延を最小限にするには?

コンテンツを圧縮し、非同期でデータを読み込めるように、エンジニアは様々なコツやライブラリを使用します。

とは言え、ある時点から物理法則が忍び寄り、単純にデータセンターとユーザーの通信をより速くする必要が出てきます。

単一のデータセンターでプロダクトを実行していて、物理的な近さが有益なこともあります。この場合、移動 (引っ越し) は選択肢にはありません。おそらく、キャッシュ化を行うか、静的資源に CDN を使用します。

物理的な所在地にそこまで縛られない場合、または Indeed のように複数のデータセンターを運用している場合、データセンターを移すことが鍵かもしれません。

だけど、どうやって選べばいいのでしょうか?

シンプルな選び方としては以下のようなものがあります。

 

口コミ 

良い値段だし、そのデータセンターの他の顧客にも聞いたら、満足しているようだ。データセンターが提供するインターネット会社のリストも対象範囲は広いみたいだし、多分自社ユーザーにもぴったりだろう…

運が良ければの話です。

 

地理  

東海岸には沢山アメリカ人ユーザーがいる。近くに(例えば NY 辺りに)データセンターがあれば、東海岸の作業が速くなるに違いない…

 

がっかりする準備はいいですか。

 

上記は、データセンターを選ぶ理由として、ひどいというわけではありません。

しかし、インターネット上の経路は地理に基づかず、ネットワークの相互接続部分、企業戦略、そして値段などに基づきます。

物理的に、データセンターが顧客サイトのユーザーのどんなに近くだとしても、もしユーザーの ISP が自社で所有する施設への専用ファイバーを持っていて、ニュージャージー経由でニューヨークに接続する方がその ISP にとって安いのであれば、おそらくそうするでしょう。

インターネットの「配管」は、必ずしも私たちの想像するようには接続されていないのです。

Indeed の取り組み

2012年の10月、Indeed は同じような苦境に立たされました。

米国中に点在してデータセンターを所有していましたが、西海岸の施設はほぼ一杯になっており、予想される私たちの成長スピードでは、かなり厳しい状況になるとプロバイダに警告されていました。

Ops チームは、データセンターの代替を積極的に考えていましたが、西海岸のユーザーに遅れが発生することは望ましくありませんでした。

そうして数か所のデータセンター内に、テストサーバーを設定しました。テストサーバーに、できるだけ多くの場所から ping を送り、その結果を元々のデータセンターの ping にかかる時間と比較しました。

これは、ひどいアプローチではなかったものの、速さを追求する求職者のエクスペリエンスを模倣したものではありませんでした。

その間、他の部署でもこの問題について考えていました。

そうして、エンジニアリング・マネージャーとの廊下での何気ないやりとりから、今日私たちが使用しているメソッドに雪だるま式に発展しました。

本物のユーザーリクエストを使用して、可能性のある新しいロケーションをテストすることが重要でした。

なんにせよ、ユーザがどのようにデータセンターを感じるかということについて、同じユーザを使うことに勝る手段はありません。

数度に亘る議論の末、そして、開発  (Dev)  と運用 (Ops) の仕事の末、フルーツテストを私たちは生み出しました。

これは、フルーツを基にしたテストサーバーのホスト名にちなんで名付けられました。

このテクニックを使用して、提案されていた新しいデータセンターは、ほとんどの西海岸の求職者のレスポンスタイムから平均し 30ms 削れると私たちは予想しました。

全てのフットプリントを新しい施設に移行した後、私たちはこの数字が正しかったことを確認しました。

その仕組み

まず、使用できる可能性のありそうなデータセンターが、対象になるかを調査しました。

スペースやコストのせいで不適切な環境に対して、テストを実行するのは無意味です。

そのハードルをクリアした後には、軽量な Linux のシステムと Web サーバーを設定します。

この Web サーバーは、 lemon.indeed.com のように、フルーツにちなんだ名前を持つ仮想ホストを一つもっています。

その仮想ホストが 0.js1.js、というように最大 9.js まで名付けられた 10 件の静的な JavaScript ファイルを配信できるように設定します。

サーバーが準備でき次第、 Proctor 内にテスト・マトリックスを設定します。 Proctor は自社開発したオープンソースの A/B テスト・フレームワークです。

各テストバケットに、フルーツとパーセンテージを割り当てます。それからサイトへの各リクエストは、パーセンテージに基づいてランダムにテストバケットの一つに割り当てられます。

各フルーツは、 (新規、既存のどちらにせよ) テスト中のデータセンターに対応します。

テスト・マトリックスを本番環境にパブリッシュしたら、ここからは楽しい工程が待っています!

fruit-flow

図 1:フルーツテストのリクエスト、応答、ログ

図例

  1. サイトはクライアントにフルーツテスト実行を指示。
  2. 0.js のリクエストと応答が dcDNSCallback を呼出。
  3. dcDNSCallback0.js のリクエストのレイテンシーをサイトに送信。
  4. [1-9].js のリクエストと応答が dcPingCallback を呼出。
  5. dcPingCallback[1-9].js のリクエストのレイテンシーをサイトに送信。

テストバケット内のリクエストは JavaScriptを受信します。その JavaScript は、ブラウザに対して、タイマーを開始し、選択したフルーツのサイトから 0.js のファイルを読み込むように指示します。このファイルは空のコメントと dcDNSCallback の関数を呼び出す指示を含みます。 lemon.indeed.com では “l” を渡して、テストフルーツを示します。

/*

*/
dcDnsCallback("l");

その後、dcDnsCallback が以前のタイマーを停止し、 indeed.com にリクエストを送信します。
これは、測定したリクエストのレイテンシをログします。

dcDnsCallback の関数は2つの目的があります。

ユーザーのシステムは DNS キャッシュの中にフルーツのホスト名の IP アドレスをおそらく持たないので、 DNS 解決と、一回のリクエストの応答にどれくらいの時間がかかるのか、わかるのです。

それから、このセッション内でのそのフルーツホストへの後続のリクエストは、 DNS の解決にほとんど時間がかからないので、応答時間を計った結果がより正確になります。

dcDnsCallback の呼び出し後、テストは9個の静的な JavaScript ファイルをランダムに選び、同じ手順 (タイマーを開始、ファイルを取得、ファイル内で関数の実行) を繰り返します。これらのファイルは以下のような内容になっています。

/*
3firaei1udgihufif5ly7zbsqyz59ghisb13u1j26tkffr7h67ppywg12lfkg7ortt5t3xoq5
*/
dcPingCallback("l");

これら 9件のファイル (1.js から 9.js) は基本的に、 0.js と同じですが、 dcPingCallback の関数を代わりに呼び出し、全体の応答の長さを定義済みのサイズに調整するコメントを含みます。

1.js は最小で、たったの 26B ですが、 9.js は重く、 50KB もあります。

異なるサイズのファイルを持つ事で、レイテンシが低いけれど、利用可能な帯域幅が限定されるため、大きなファイルには不釣り合いに時間を食うデータセンターを調査しやすくなりました。

また、これは帯域幅が充分広いため、処理という観点では、処理開始時の TCP 接続の確立に一番時間がかかるようなデータセンターを識別してくれます。

dcPingCallback の関数が実行されるとすぐに、タイマーは止められ、フルーツ、 JavaScript のファイル名、読み込みにかかった時間の情報は、 Indeed に送られ、ログされます。

これらのリクエストは、表示されたブラウザのページの末尾におかれ、ユーザー・エクスペリエンスにおいて、テストの影響を最小限にするため、非同期で実行されます。

indeed.com において、ログを取るエンドポイントはこのデータを受信し、ソースの IP アドレスとユーザーが見ているサイトを記録します。

それから、 Logrepo と Indeed で呼んでいる (ええ、謎な名前ですよね)  特別な形式になったログストアに、その情報を書き込みます。Logrepo のログを集めた後、 Imhotep を使用しインデックスを作ります。これはクエリや、グラフ作成を楽にしてくれます。

テストの性質により、私たちはフルーツテストを数週間実行し、本物の求職者から何十万、果ては何百万とサンプルを集め、情報に基づいた意思決定を行えるようにします。

テストが終了したら、 Proctor のテストをオフにし、フルーツテストのサーバーをシャットダウンしてしまうだけで終わりです!他にインフラ的な変更は不要です。

 

このアプローチの良い点は、他のタイプのテストにも柔軟なところです。

もちろん、新規のデータセンターの所在地をテストする際に主に使用しますが、もしこのアプローチを重要な部分に煮詰めると (まさにフルーツジャムと一緒!)、テストのすることといえば、決められた量のデータのセットを、ランダムなユーザーのサンプルからダウンロードし、かかった時間を教えてくれることです。

この結果を解釈するのは、テストのデザイナー次第です。

データセンターのテストをする他にも、2つの異なるキャッシュ技術をテストしたり、異なるバージョンのウェブや、アプリのサーバーの性能の違いをテストしたり、または、  Anycast/BGP IP の地理的な分散 (過去に実施済) を調べることができます。

サンプルのサイズが、統計的に充分多様であれば、有効な比較が可能ですし、最適な人々、つまりユーザーの視点から、それを得ることが出来るのです。

いいけど、なんでフルーツテスト?

現行の、それから今後使用する可能性のあるデータセンターの所在地を表す、ユニークな名前を考えた際、私たちが考えたのは以下の様な名前でした。

  • 運用 (Operations) チームが簡単に識別できること
  • ユーザーには曖昧で、かつ、あまりミステリアスすぎないこと
  • ビジネス上で意味をもたないこと

アルファベットの文字に対して異なるフルーツを考えるのは非常に簡単だったので、デザインをする中でプレースホルダとしてフルーツを使用しました。そして、デザインを進めていくにつれ愛着が湧き、結果採用した、というわけです。

チケットを開いて、ナツメ、マルメロ (筆者のお気に入り)、エルダーベリーのテストを有効にするのは、味のある作業です!fruits-82524_640

で、その後は?

データを山ほど集めたところで、がんがんグラフにしていきます!

そんなわけで、フルーツテストのシリーズ第二弾に続きます。

Status:堅牢なシステム・ヘルスチェックのための Java ライブラリ

今回は Status (ステータス) のオープンソース化を特集したいと思います。

Status は、システムのステータスを読みやすいフォーマットでレポートできる Java  ライブラリです。この Status ライブラリは動的なヘルスチェックと、システムの依存関係の監視を可能にします。

この記事では、皆さん自身のアプリケーションにヘルスチェックを追加する方法を説明します。

システムステータス・ヘルスチェックを使用する理由は?

ヘルスチェックは、 Indeed で重要な役割を果たしています。

私たちは毎日大規模のサービスやアプリケーションをセットアップし、実行しています。

ヘルスチェックは、問題のあるコンポーネントをログからくまなく探すのではなく、エンドポイントでの発見を可能にします。

 

本番環境では、サービスが到達不能であったり、ファイルが見つからない場合、またはシステムがデータベースに接続できない場合にヘルスチェックが通知してくれます。

加えて、これらのヘルスチェックは、開発者が制御された方法でシステム管理者に問題を通知する方法を提供します。

これらのどんな状況でも、アプリケーションは全システムをオフラインにするのではなく、自身のヘルスチェックを評価し、挙動をグレイスフルデグラデーションすることが可能になります。

Status ライブラリは依存関係のスタックトレースをキャプチャし、その結果を一つの場所に返します。この機能は、問題がどの環境で発生しても、解決を容易にしてくれるのです。

典型的な依存関係には、 MySQL テーブル 、 MongoDB のコレクション、 RabbitMQ のメッセージキュー、ならびに API のステータスなどがあります。

システムの状態

依存関係に障害が発生した場合、システムの状態に影響します。

システムの状態は以下のように表示されます。

  • OUTAGE (停止)  – システムがリクエストを全く処理不可能な状態
  • MAJOR (重要度:高) – システムが一部を除き殆どのリクエストを提供不可能な状態
  • MINOR (重要度:低) – 一部を除き殆どのリクエストを提供可能な状態
  • OK – システムが全てのリクエストを処理可能な状態

Status を始めてみよう

以下の手順に従い、早速 Status ライブラリを使ってみましょう。

AbstractDependencyManager を継承したクラスを作成します。これは、全ての依存関係を追跡してくれます。

public class MyDependencyManager extends AbstractDependencyManager {
  public MyDependencyManager() {
    super("MyApplication");
  }
}

アプリケーションが実行を必要とする各コンポーネントに PingableDependency を継承します。

public class MyDependency extends PingableDependency {
  @Override
  public void ping() throws Exception {
    // Throw exception if considered unhealthy or unavailable
  }
}

PingableDependency のクラスを継承するのが、アプリケーションに依存性を統合するのに最もシンプルなやりかたです。

それとは別に、 AbstractDependencyComparableDependency を拡張すると、依存関係の状態をさらに管理することができます。緊急度レベルを提供すると、依存関係が、システムの状況にどう影響するかをコントロールできます。
新しい依存関係を、 dependency manager に追加します。

dependencyManager.addDependency(myDependency);
...

Web ベースのアプリケーションやサービスには、アプリケーションのステータスをレポートしてくれる AbstractDaemonCheckReportServlet を作成します。

public class StatusServlet extends AbstractDaemonCheckReportServlet {
  private final AbstractDependencyManager manager;

  public StatusServlet(AbstractDependencyManager manager) {
    this.manager = manager;
  }

  @Override
  protected AbstractDependencyManager newManager(ServletConfig config) {
    return manager;
  }
}

このプロセスが完了し、アプリケーションが実行された時点で、アプリケーションのステータスを JSON で表現するサーブレットにアクセス可能になります。

以下はサーブレットが返すリスポンス例になります。もしアプリケーションが OUTAGE (停止) の場合、サーブレットは 500 というステータスコードを返します。ヘルスチェックの結果を HTTP のステータスコードと関連付けると、アプリケーションの稼働状態に基づいて経路決定をするシステム(例 Consul )と統合可能になります。そうでなければ、アプリケーションはリクエストを処理できるので、サーブレットはステータスコード 200 を返します。この場合アプリケーションは、正常でないコードパスに依存する、重要度が低い機能をグレイスフルデグラデーションすることができます。

{
  "hostname": "pitz.local",
  "duration": 19,
  "condition": "OUTAGE",
  "dcStatus": "FAILOVER",
  "appname": "crm.api",
  "catalinaBase": "/var/local/tomcat",
  "leastRecentlyExecutedDate": "2015-02-24T22:48:37.782-0600",
  "leastRecentlyExecutedTimestamp": 1424839717782,
  "results": {
    "OUTAGE": [{
      "status": "OUTAGE",
      "description": "mysql",
      "errorMessage": "Exception thrown during ping",
      "timestamp": 1424839717782,
      "duration": 18,
      "lastKnownGoodTimestamp": 0,
      "period": 0,
      "id": "mysql",
      "urgency": "Required: Failure of this dependency would result in complete system outage",
      "documentationUrl": "http://www.mysql.com/",
      "thrown": {
        "exception": "RuntimeException",
        "message": "Failed to communicate with the following tables:
          user_authorities, oauth_code, oauth_approvals, oauth_client_token,
          oauth_refresh_token, oauth_client_details, oauth_access_token",
        "stack": [
          "io.github.jpitz.example.MySQLDependency.ping(MySQLDependency.java:68)",
          "com.indeed.status.core.PingableDependency.call(PingableDependency.java:59)",
          "com.indeed.status.core.PingableDependency.call(PingableDependency.java:15)",
          "java.util.concurrent.FutureTask.run(FutureTask.java:262)",
          "java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)",
          "java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)",
          "java.lang.Thread.run(Thread.java:745)"
        ]
      },
      "date": "2015-02-24T22:48:37.782-0600"
    }],
    "OK": [{
      "status": "OK",
      "description": "mongo",
      "errorMessage": "ok",
      "timestamp": 1424839717782,
      "duration": 0,
      "lastKnownGoodTimestamp": 0,
      "period": 0,
      "id": "mongo",
      "urgency": "Required: Failure of this dependency would result in complete system outage",
      "documentationUrl": "http://www.mongodb.org/",
      "date": "2015-02-24T22:48:37.782-0600"
    }]
  }
}

このレポートは、システムの動作状態と依存関係の状態を評価するのに役立つ、これらの主要なフィールドを含みます。

condition システム全体の現在の稼働状態を識別する。
leastRecentlyExecutedDate レポートが最終更新された日付と時間。

個別の依存性を調査するには、以下のフィールドを使用します。

status 現在の依存関係の状態を識別する。
thrown 依存関係に障害をもたらした例外 ( exception )。
duration 依存関係の状態を評価するのにかかった時間の長さ。 システムが依存関係の評価の結果をキャッシュしているので、この値は 0 にもなり得る。
urgency 依存関係の緊急度。 WEAK (弱) の緊急度をもつ依存関係は直ちに修復しなくてもよい。 REQUIRED (要) の緊急度を持つ依存関係は可能な限り早い修復が必要とされる。

Status をさらに知ろう

今後の Status ライブラリ使用法を特集する記事では、正常に稼働していないアプリケーションに対し、どのようにグレイスフルデグラデーションを行うかをお伝えする予定です。

 

status の使用を始めるには、クイックスタートガイドや、サンプルをご覧ください。

お困りの際は GitHub または Twitter からご質問いただけます。

コンピューターサイエンス論文から優秀な(使える)アイデア発掘

結構な時間をかけて、最近のコンピューターサイエンスの論文を読み漁っている。

自分のチームのプロダクトを改善してくれそうな、アルゴリズム的な物を何でも探しているのだ。

これも Indeed のミッションである Help People Get Jobs のため。成果はまちまちで、 Indeed では活用できそうにない美しい数式しか見つからないこともしょっちゅうある。

でも、コンピューターサイエンスの文献を読み込むことで、得られるものは沢山ある。

もっと多くのソフトウェア開発者が、文献を活用して腕を磨いてもいいんじゃないだろうか。

 

inverted-index-words

Word cloud generated by WordItOut

コンピューターサイエンスの論文を読む理由とは

「何で?」- そもそも、こう思うんじゃないだろうか。

現役で仕事をしている開発者は、やはり論文なんか読まないだろう。

事実、僕が文献サーチを勧めると、何人もの優秀な開発者にぽかんとした顔つきで見られた。

「え? StackOverflowを見ろってことかい?」という具合に。

理由を簡潔に答えるなら、それは問題解決で優位に立つためだ。

(場合によっては競合会社や、同僚から抜きんでるため、でもあるだろう。)

一部の研究者は、君の抱える課題がより深く一般化された問題について研究している。彼らは問題解決に対して(場合によっては研究費用確保という意味でも)ハングリーで、ソリューションをタダでくれる

また、大学の終身雇用枠候補から追い出されないように、彼らはものすごいペースで論文を発表している。

研究者は、きちんとした実装可能なアプローチを考えだし、それを気前よく無料でくれるのだ。

そして 一番クレイジーなのは、この事実を、ほとんどの人が知らないし、気に掛けてもいないってこと。

でも、賢い開発者なら、このクレイジーな状況をしっかりと活用して成果をあげられるんじゃないだろうか。

肝心なのは、文献から自分に役立つものを見つけて、研究者が言わんとしていることを読み解くことだ。

 

役立つ論文の見つけ方

何千ものコンピューターサイエンスの論文が、毎年発表される。

その中から、読むに値する論文を探すには一体どうすればいいか?

今世紀の多くの問題と同じく、ここでも Google が答えを持っている。

それは、 Google Scholar だ。

僕の知る限りでは、 Google Scholar は現存する研究論文をほとんど全て提供している。しかも無料で。アラン・チューリングの時代からのコンピューターサイエンスの論文を、ほぼ全て読むことができるのだ。

Google Scholar は、これまでどんな会社が無償で提供したサービスの中でも、最も素晴らしいものの一つだ。

一部のリンクには有料の論文も含まれているけれど、たいていの場合は、そこにも無料の論文への追加リンクがある。

僕はこれまで何百もの論文を読んできたが、一度としてお金を払ったことはない。

Google はこれをマネタイズしようともしていないのだ。

scholar.google.com というサイトを聞いたことがある人は、一般市民では殆ど誰もいないだろう。さらに驚くことに、 Google 関係者の話によると、 グーグラー(Google 社員)ですら、この存在を知る人はあまり多くないそうだ。

Google Scholar のおかげで、「興味深い論文を探す」という課題は、これでクリアできた。

 

論文の見分け方

次の課題は、「見つけてきた面白そうな文献を振り分け、優先順位をつける」ということ。

Google Scholar の探索アルゴリズムは強力だけれど、万能というわけではない。

自分の持つ検索スキルを駆使しても、読み切れないほどの、そして理解しきれないほどの論文が引っかかってくるだろう。

手に取った論文が、君の課題に一番役に立つものだという可能性は低い。

最も関連性の高いものを、簡単に見つけるコツはこうだ。

まず、論文の発表年月日を見つけ出す。

簡単にわかるメタデータの一部に見えるけれど、実は、論文自体に日付は滅多に書かれていない。そうする代わりに、 Google Scholar の中でヒントを探そう。

参考文献リストの中で、最新の日付を持つ論文の出版年月日から2年後くらいが論文の発表時期だと推測するのも良いだろう。これは雑なようでいて、かなり効果的な方法なのだ。発表から 15 年以上経っているコンピューターサイエンスの論文は、歴史的興味以上の価値が殆どない。

その上で、論文の初めのパラグラフを読む。

ここで、研究者は取り組んだ問題と、その重要性を述べている。

自分の抱える問題と似ていれば、ラッキー!

自分の問題に似ていない場合、論文の結果そのものが君の興味をくすぐる、などがなければ、読むのを止めて、次の論文にうつろう。

もし、関連性が期待できそうな内容なら、 2 パラグラフ目まで読み進めよう。

2 パラグラフ目では、どんな調査をしたか、制約、そして結果の概要を教えてくれる。

自分の環境で彼らが行った事を再現できて、制約を受け入れられて、結果が良ければ、ビンゴ!

どうやら読む価値ありの論文のようだ。

 

論文の読み方

研究論文を読む上で一番の秘訣とは何か。

それは「どこを読んで、どこを読まないようにするかを理解しておく」 ことだ。

学術論文は、 ソネット14行詩) の厳密な構造よりも、やや柔軟くらいな構造に従って書かれている。一見すると内容理解に役立ちそうな箇所が、かえって混乱させるだけだったりする。反対に、一見すると要領の得ない、不明瞭な箇所が、論文の深い意味をくみ取る鍵を持っていたりする。

さて、僕の論文へのアプローチはこんな感じである。

 

要約を読まない。

要約は、同じ分野の研究者たちに向けて書かれた論文の要旨だ。

過去 10 年くらい同じような問題にずっと取り組んできた、いわば同業者たちに向けて書かれている。君は、まだそのレベルには達していないだろう。

要約を読んでも混乱するだけだし、かえって意気消沈してしまうかもしれない。

要約はトピックの理解を助けてはくれない。

 

キーワードも読まない。

論文にキーワードを盛り込むのは、依然として残っている悪しき慣習だ。キーワードは誤解を招くことが多いし、新しい情報はまず含まない。飛ばしてしまおう。紙面の無駄なのだ。

 

論文の本文はしっかり読む。 

中学生の時に、先生から叩きこまれた研究テクニックを覚えているだろうか? それをフル活用しよう。

君がやろうとしていることは、研究者が行ったこと、その手段をリバースエンジニアリングすることだ。これは、工夫を要する作業かもしれない。

まず論文には、研究の裏側で共有された沢山の仮定や、詳細や、小さなつまずき等が省略されている。一字一句読み込もう。

また、知らない言い回しや単語は調べよう。 Wikipedia が、だいたいの場合役に立つはずだ。

そして疑問を書きだそう。研究者が行った事だけでなく、行わなかった事と、その理由も考えてみよう。

 

コードを読まない。

これは、直観に反するように聞こえるかもしれない。

ソフトウェアの開発者にとっての一番のコミュニケーション手段は、コードだからだ。

理想をいえば、ドキュメンテーション、バージョン履歴、相互参照、テストケース、レビュー・コメントなどもあると尚良い。

研究者は、そうは思っていない。大雑把に言うと、研究論文の中のコードは無価値だ。上質なコードを書くのに必要なスキルは、興味深い学術論文を書くのに必要なスキルと直交するか、はっきりと対立している。

研究の中で使用されたコードの殆どが、レビューを受けておらず、バージョン管理されておらず、テストケースを持たず、そしてデバッグも 「ほぼクラッシュしなかったね。今日のところは。」 というレベルでしかされていない。

そんな事実も、研究者にしてみれば取るに足らないことなのだ。それですら、まだ良いほうだ。

ひどいコードは、単純に無効だったり、論文が発表された時には、もう削除されていたりする。(これは本当にひどい。コンピューターサイエンスの分野ですら、この有様なのだ。)

 

等式は読む。

研究者は、数学のことは熟知している。

彼らの書く等式は、開発者が、優れたソフトウェアに見出す美徳を全て兼ね備えている。

つまり、精度、正確さ、簡潔さを持ち、示唆に富んでいるのだ。

さらには、その等式にすら欠点を必死に探そうと、賢い人々の集まりが、苦心して等式をレビューしている。

反対に、論文内のコードは、ちょっと暇な大学院生が書いており、誰も読まない類のものだ。

 

結論部分は読まない。

ここに新しい情報は特にない。

 

論文を活用して、さらなる探索を

研究論文は他の論文を参照することで、コンテクスチュアル・データの恩恵を与えてくれる。 Google Scholar は、論文を探すことに秀でている。それでもやはり、一番有益なのは、研究者が参照した論文を実際に追いかけることだろう。

 

関連研究内の引用を追う。

「関連研究」 の節で、執筆者は自身の研究に重要な他の研究に対し、示唆に富んだ説明を書く。これは、彼らの研究を紐解く際におもしろい対比となる。ある意味、この箇所は、最も重要な他の研究との関連性を記録しているからだ。

 

参考文献内の引用を追う。

HTML のおかげでハイパーテキストが広まるずっと前から、研究論文は、相互参照という大きな森を抱えていた。つまり、引用のことである。

最も優れた研究でも、その価値の半分は本文にあり、もう半分はリンクにある。

論文の中の引用は (まだ) クリックして飛べるものではないけれど、 Google Scholar を使えば引用を追う事はそう難しくないはずだ。

古い論文が頻繁に引用されているなら、それはきっと、その分野では重要なもので、文脈に有益である可能性が高い。

新しい論文が頻繁に引用されているなら、その問題への取り組みの軌跡を洞察しているのではないだろうか。

また、問題とのつながりが一見すると不明瞭で不思議な引用論文は、仮説を立てる時など一旦距離を置いて考えることに役立つはずだ。

 

これが全部できたら…

あとはコードを書くだけ。さあ、やろう!

デイブ・グリフィスは Indeed のソフトウェアエンジニアで、ソフトウェアシステムの開発に 20 年以上携わっています。