10/14/17

Java 8の機能利用に伴うSpring 4へのバージョンアップ

下記の順序で環境を更新していったときに、問題が起こったのでメモしておきます。
  1. Spring 3 + Java 7: もともとの環境。
  2. Spring 3 + Java 8 (Java 8のラムダ機能などのJava 8からの新機能は未使用): 問題なく動作。
  3. Spring 3 + Java 8 (Java 8のラムダ機能などをJava 8からの新機能を使用): 起動時に下記のExceptionが発生
    org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: URL
    ...(途中省略)...
    java.lang.ArrayIndexOutOfBoundsException: xxx
    
Googleで調べたところJava 8から導入された新機能を使う場合は、Spring 4に更新しないといけないようです。
Mavenとかは、使っていなかったので、Spring Frameworkから提供されているspring-xxx系のjarすべてをバージョン3.X系からバージョン4.X系のものに手動で置き換えました。
(Spring Frameworkはバージョン5.X系ももう出ているのですね。既に置いていかれているorz...)
無事にアプリケーションが起動するようになりました!
ただ普通は、こんな乱暴にjarを入れ替えることは難しいので、アップデートはもっと慎重にやるべきでしょうね。

Google App Engineで外部のURLにアクセス

Google App Engine(GAE)から外部のネットワークへ接続する際の注意

Google App Engine(GAE)の開発環境の移行の際にJava 7からJava 8へ移行しました。
その際、GAEから、java.net.URL.openConnectionを使って普通に外部ネットワークのAPIを呼び出そうとすると下記のエラーが発生するようになってしまいました。
java.net.UnknownHostException: ホスト名
いろいろ調べていくと、下記のページにたどり着きました。
https://cloud.google.com/appengine/docs/standard/java/issue-requests
上記の表を間単に日本語訳すると
URLのフェッチ方法 Java 7 Java 8
UrlFetch API Calls com.google.appengine.urlfetch.*以下のクラスを使う。無料で使用できる部分あり。 com.google.appengine.urlfetch.*以下のクラスを使う。無料で使用できる部分あり。
Javaネイティブのjava.net.URL.openConnectionなどを使う方法 無料ユーザも制限なく利用可能。 無料ユーザは、利用不可。
java.net.UnknownHostException、java.net.SocketTimeoutException、java.io.IOException とかが投げられる。
まとめると、
  • GAEで外部ネットワークへアクセスする方法には「GAEが提供するUrlFetch API Calls」「Javaネイティブのjava.net.URL.openConnection」の2つ方法がある。
  • Java 7では、「GAEが提供するUrlFetch API Calls」「Javaネイティブのjava.net.URL.openConnection」は無料でどちらの方法も利用可能。
  • Java 8で無料で利用できるのは「GAEが提供するUrlFetch API Calls」のみ。
  • Java 8で「Javaネイティブのjava.net.URL.openConnectionの方法」は課金ユーザーのみ利用可能。

コードの変更

変更前: Java Nativeのjava.net.URL.openConnectionを使う方法

import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;

// 余計な部分も混じっていますが、外部のデータをbyte[]形式で取得するコード
public static byte[] readAsBytes(final String urlStr)
 throws MalformedURLException, URISyntaxException, IOException, ProtocolException {
  URL url = new URI(urlStr).toURL();
  HttpURLConnection connection = (HttpURLConnection) url.openConnection();
  connection.setDoOutput(true);
  connection.setRequestMethod("GET");
  connection.connect();
  byte[] bytes = toBytes(connection.getInputStream(), 2000);
  connection.disconnect();
  return bytes;
}

変更後: Java Nativeのjava.net.URL.openConnectionを使う方法

import com.google.appengine.api.urlfetch.URLFetchService;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;

public static byte[] readAsByte(String urlStr) throws MalformedURLException, IOException {
    URLFetchService service = URLFetchServiceFactory.getURLFetchService();
    HTTPResponse response = service.fetch(new URL(urlStr));
    return response.getContent();
}

10/13/17

Goolge App Engineの開発環境の更新 (Java)

Google Plugins for EclipseからCloud Tools for Eclipseの移行

長らくEclipse Luna (4.4) + Google Plugin for Eclipseで開発を続けてきたのですが、Google App Engineの開発ページを覗いたら下記のようなメッセージが出ていてびっくり。

The Google Plugin for Eclipse is deprecated and will be removed in January 2018. Migrate to Cloud Tools for Eclipse and/or the GWT Eclipse Plugin as soon as possible to avoid disruption.

Google Plugin for Eclipseは、2018年の1月でサポート打ち切りで、Cloud Tools for Eclipseに移行しなさいとのこと。
せっかくなので最新のeclipseを使って下記の設定で開発環境を再構築することにしました。

移行方法

  1. 最新のJDK 8 をhttp://www.oracle.com/technetwork/java/javase/downloads/index.htmlからダウンロードしてインストール。JDKをダウンロード Java 9 も試そうかとも思ったのですが、2017年9月現在Google App Engine側はまだJava 8までしかサポートしていないので、
  2. Eclipseを http://www.eclipse.org/downloads/eclipse-packages/ からダウンロード。私は、Eclipse IDE for Java Developersをダウンロードしました。
  3. EclipseでGoogle App Engineの開発を行うための設定をhttps://cloud.google.com/eclipse/docs/quickstart を読んで実施。
    1. Google Cloud SDKをダウンロード
    2. Google Cloud Tools for Eclipse をEclipse Marketplace.を通してインストール
  4. 古いプロジェクトで無理やりApp Engine SDK内のjarを参照して開発していたので、App Engine SDK もhttps://cloud.google.com/appengine/docs/standard/java/downloadからダウンロード 。(このステップは不要かも)
新規のGoogle App Engineのプロジェクト構築は、公式ドキュメントどおりに作成すればよいので、説明は割愛します。

ここでは、旧Google Plugins for EclipseのプロジェクトをCloud Tools for Eclipseに移行したときの作業を簡単に書こうと思います。結論からいうと移行はかなり苦労しました。

移行手順

  1. まずはworkspaceを新規に作成してEclipseのメニュー「Import > Existing Project into Workspace」を選択して、旧Google Plugins for Eclipseのプロジェクト
  2. appengine-web.xmlでjavaのruntime versionをjava 8に指定。
    <runtime>java8</runtime>
  3. Eclipseのプロジェクトを右クリックしてメニューの「Configure > Convert to App Engine Standard Project」を選択して、Google App Engineのプロジェクトに変更。
  4. 実行に必要なJarファイルへのBuild Pathをマニュアルで設定。例えばJUnitでData Storeへのテストで参照していたcom.google.appengine.tools.development.testing.*以下のクラスが含まれるjarファイルappengine-testing.jarをBuild Pathに追加しました。
  5. xmlファイルのスキーマチェックので色々エラーが出たので細かく修正。
  6. Eclipse上でコンパイルエラーが出なくなる。万歳!

移行で苦労したところ

コンパイルまで通ったので、早速Google App EngineのWebアプリケーションとして起動して、移行完了かと思いましたが、Google Data Storeの部分で思わぬ落とし穴にはまってしまいました。
  1. pluginによるORMのサポート打ち切り!

    Google Plugins for EclipseではDataNucleasがプラグインの中に含まれていて、Eclipse上で下記のような設定をすれば、DataNucleus Enhancerが起動してクラスをEnahnceしてくれました。

    が、Cloud Tools for Eclipseでは、その機能自体がなくなってしまいました。Data Storeへのアクセスが発生する部分で下記のExceptionが出てしまいました。
    DataNucleusを使用したい場合は、自分でMavenやpluginを使ってDataNucleusの設定をしなければいけないようです。しかもGoogleは、赤字でこんなことまでアナウンス
    Warning: We think most developers will have a better experience using the low-level Datastore API, or one of the open-source APIs developed specifically for Datastore, such as Objectify. JPA was designed for use with traditional relational databases, and so has no way to explicitly represent some of the aspects of Datastore that make it different from relational databases, such as entity groups and ancestor queries. This can lead to subtle issues that are difficult to understand and fix.
    いい加減に意訳すると「最近のディベロッパーは下層レベルDatastoreのAPIや、Datastore専用に作られたObjectifyといったAPIを使っているから、伝統的なRDB用のJDOやJPAではGoogleのDatastoreは使いこなせないよ!」とのこと。
    GoogleのDataStoreをそんなに使っているアプリケーションではなかったので、今回は移行スピード最優先でDataStoreへのアクセス部分を切り離して、アプリケーション起動するところまでもっていきました。後日、DataNucleusを使って動かすところまで持っていこうと思います。
  2. "No such servlet: jsp"エラー(回避はできたが、根本解決していない。原因調査中)
    Google App Engine上のアプリケーションではSpring Frameworkを使って開発していました。ローカルで起動して動作確認したときは、全く問題なかったのですが、Google Cloud 上にデプロイしたところ、下記のエラーが発生しました。
    java.lang.IllegalStateException: No such servlet: jsp
    at org.eclipse.jetty.servlet.ServletHandler.updateMappings(ServletHandler.java:1535)
    at org.eclipse.jetty.servlet.ServletHandler.doStart(ServletHandler.java:157)
    ...
    
    Googleでも色々検索したのですが、原因がさっぱりつかめず、結局エラーメッセージを額面どおりに受け取って「サーブレットの定義がない」ということで、web.xmlに
    <servlet>
      <servlet-name>jsp</servlet-name>
      <servlet-class>空のダミーサーブレットクラス</servlet-class>
      <load-on-startup>1</load-on-startup>
    </servlet>
    
    を追記したところ、Google Cloud上では動作するようになりました。
    が、この設定を加えたことで開発環境では逆に動かなくなってしまいました。今は、本番にデプロイするときだけ、上記のservletの設定を加えるようにして当面は凌ぐ予定です。

ここまでやってようやくGoogle Plugins for EclipseからCloud Tools for Eclipseへ移行できました。DataStoreまわりはこれからなので、完全な移行はもっと時間がかかりそうです。

7/30/17

「コンサルタントの秘密―技術アドバイスの人間学」(ジェラルド・M・ワインバーグ 著)

今回紹介する本は、ジェラルド・M・ワインバーグの「コンサルタントの秘密―技術アドバイスの人間学」です。


原著は「The Secrets of Consulting: A Guide to Giving and Getting Advice Successfully」です。私なりに訳してみると「コンサルティングの秘密: 上手なアドバイスの与え方ともらい方」になるでしょうか。邦訳の題名は原題の内容をしっかり捉えていて上手いと思います。



原著が刊行されたのは1986年で、この記事を書いている時点で30年以上も前になりますが、本書の内容は今でも通用するアドバイスばかりです。本書の内容は、誇張でなく、今から30年後でもまだ通用する気がします。
この本の中ではワインバーグが名づけた「~の法則」とか「~の原理」が大量に登場します。どれもユーモアに富んでいて思わずクスッと笑ってしまうものばかりです。
ほんの一例ですが、こんな感じです。

  • 逆転ワインバーグの法則
  • レッテルの法則
  • 三本指の法則
  • ポテトチップの原理
  • オレンジジュース・テスト

などなど。巻末にはご丁寧に法則集索引までついています。内容はぜひ本書を読んでご確認ください。

エッセイでもなく、教科書のように型にはまった方法論を押し付けるでもなく、それでいて学ぶところが多い不思議な本です。ユーモアに富んでいて、肩の力を抜いて読める本ですが、ワインバーグの長年の経験から得られた深い洞察の詰まったすばらしい本です。
本のタイトルには「コンサルタント」「技術アドバイス」といったキーワードが並んでいますが、これらのキーワードと直接の関係ない人にもお勧めできます。

7/28/17

「プログラミングの心理学 25周年記念版」(ジェラルド・M・ワインバーグ 著)

ジェラルド・M・ワインバーグは、自身のコンピューター業界を中心としたコンサルタント業の経験をもとに、人間やシステムの性質を本質的に捉えた数多くの書籍を発表しています。

今回紹介するのは、その中の「プログラミングの心理学 25周年記念版」になります。



25周年は、英語ではSilver anniversaryと表現されるようで、原題は「The Psychology of Computer Programming: Silver Anniversary Edition」となっています。



本書題名中の25周年というのは、原著の「The Psychology of Computer Programming」の初版が発行された1971年から25年後、つまり1998年に発行された英語版のことをさして、25周年といっています。この英語版の「The Psychology of Computer Programming: Silver Anniversary Edition」は、一度2005年に邦訳されて2005年に「プログラミングの心理学―または、ハイテクノロジーの人間学 25周年記念版」として刊行されています。今回紹介するのは、2005年に刊行された邦訳版の装丁を変えて2011年に再発刊されたものになります。ですので、おおもとの原著からは、40年経っていることになります。
本書では、1971年当時の初版の構成をそのままに、そのあとに25年後のワインバーグの振り返りが追記されるという形式をとっています。

この書評を書いている時点で、40年以上も前 (25周年を記念して加筆された部分は20年前)の内容で役に立つのと思う方も多いと思いますが、それがどうして、世の中あまり変わっていないのか、今でも十分に通用する示唆に富んだエピソードが多く紹介されています。
とはいえ12章「プログラミング言語の設計原則」で出てくる言語の話題はCOBOLとかFORTRANなので、「その言語なに?おいしいの?」「古臭い話だ!」と思う人が多いと思います。それでもよく掘り下げて読んでみると、普遍的な話題を扱っていることに気づかされると思います。これは、本書が「心理学」という言葉を使っているとおり、いつまでたっても変わらない、人間の根本的な性質を軸に書かれているからだと思います。ワインバーグは「心理学」という言葉を本書以外の著作でも(半分冗談交じりに)好んで、使っています。

本書は、プログラムを書くことを職業にしている人にとっては、技術以外の視点を提供してくれる良書だと思います。私としては、それ以上に、これからプログラマという職業に就こうとしている方、プログラムの経験はないが、プログラマを管理することになった方に是非よんでもらいたい一冊です。