snuffkinの遊び場

IT関係、スポーツ、数学等に関することを、気が向いたときに書いてます。

新人エンジニア向け勉強の心構え・コツ

このpostは新人/若手向け、これだけは知っとけTips25 Advent Calendar 2012の18日目です。

本日、は新人エンジニアの方に勉強の心構え・コツを伝えたいと思います。
私自身、多くの失敗もし、今も勉強中ですが、多少なりともお役に立てればと思います。

毎日勉強しよう

プロ野球選手が練習もせずに試合に臨んだら、どう思いますか?
どの職業でも同じだと思いますが、エンジニアも一緒です。
日々の勉強があった上での仕事です。
本番の仕事で使えるように、日々の勉強(練習)を行いましょう。

飲み会等で帰宅後に勉強できない日もあるとは思います。
しかし、できる限る毎日勉強しましょう。

知らないことは調べよう

知らない単語が出てきたときは、放っておかずに、調べましょう。
その日のうちに調べておくのが良いです。でないと大抵、調べ忘れてしまうことが多いです。
地味ではありますが、続けていると自分の幅を広げるのに効果が出てきます。

自分の情報源を持とう

Webサイト、twitterのタイムラインなど、自分の情報源を持つと勉強しやすいです。
興味ある分野の情報を入ってくるようになれば、ウォッチしつづけ得意分野として確立できる可能性が高まります。

ソースを読んで、動かそう

OSS全盛時代の今、気になったらソースを読んじゃいましょう。
そして、実際に動かしてみましょう。
記事を読むだけでは分からなかった情報が手に入るし、手を動かすことで理解が深まります。

選挙に行こう

ITだけに偏るより、世の中のいろいろなことに目を向けましょう。
世の中を知っていると、システムのあるべき姿が分かることもあるかもしれません。
職場の仲間やお客さんとのコミュニケーションで役立つかもしれません。
即効性はありませんが、社会人としては幅を広げるために、IT以外のことも知りましょう。

最後に

新人のみなさんは、多くの可能性を秘めています。
エンジニアとしても、一社会人としても成功して欲しいです。そのために、なんでも一生懸命取り組んで欲しいと思います。そして、取り組みをブログ等で発表すると、つながりが広がるし、他の人の役に立つかもしれません。
是非、豊かなエンジニアライフを過ごしてください。

Javaデータグリッド仕様「JSR-347」のリンク集

この記事は Java Advent Calendar 2012 の12日目です! 11日目は@kokuzawaさんでした。13日目は@zephiransasさんです。

そういえば、今日は12年12月12日ですね。皆さんは、12時12分12秒に何をしていましたか? 私はというと、、、普通に定食屋でお昼を食べてました。。。

早速ですが、JSR-347ってご存知ですか?数字で言われても、分かる訳ないですよね?
JSR-347は「Data Grids for the Java Platform」というJSRのことです。。。って名前を聞いても、普通は何を言っているのか分かりませんよね?

まず、Data Gridとは何なのか、JSR-347とは何なのか、簡単に説明します。

Javaデータグリッド仕様「JSR-347」って何?

そもそも、JSR-347以前にはJSR-107「JCACHE - Java Temporary Caching API」というものがあり、JavaキャッシュAPIが議論されていました。ここでは、keyやvalueにJavaオブジェクトを指定して保持できるキャッシュについて議論されていました。

世の中的にはビッグデータの流れもあり、単なるキャッシュではなく、分散実行等の機能を持ったものを「Data Grid」と呼び、JavaのData Gridの仕様を決めよう。。。というのが、JSR-347です。単刀直入に言うと、メモリに乗るデータは、分散環境でメモリに乗せて実行すれば高速に処理できるよね!ということ。

さて、実際にJSR-347のGitHubにあるProposed featuresを見てみると、以下のようなものが挙げられています(もっと具体的な内容については、このポストの最後にリンク集を付けたので、そこにあるスライドをご参照ください)。

  • Async API (Future based)
  • Distributed code execution
  • Group API
  • CDI (Contexts and Dependency Injection) integration
  • Transactions (JTA) integration
  • Operation Mode
  • Eventually Consistent API
  • Configuration
  • Drop-In Replacement for JSR-107 Compliant Caches

そして、これらを実際に実装しているOSSが、RedHat社を中心に開発しているInfinispanです。
InfinispanはJava(とScala)で実装されており、超簡単に言うと、In-Memoryでクラスタ環境で動作するKVS(KVSというと狭すぎますが)です。keyとvalueにはJavaオブジェクトを利用することができます。商用製品ですと、Oracle社のCoherenceが同様の機能を持っています。

そんな訳で、JavaのData Grid仕様に関する情報や、その実装であるInfinispanの情報をまとめてみました。興味が湧いた方は是非この先のリンクをご覧ください。

JSR-347関連リンク

Infinispan関連リンク

新人向け、Eclipse便利機能(入門)

こんばんわ。
このポストは「新人/若手向け、これだけは知っとけTips25 Advent Calendar 2012」の2日目として、書いています。1日目はtoshikiさんによる「エディタのちょっとした設定」でした。

さて、2日目ですが、私が開発で利用する言語はJavaがメインのためJavaの開発環境について書きます。
現在、多くのJavaエンジニアが開発環境としてEclispeを使っているのではないでしょうか。そこで、ここでは「新人向け、Eclipse便利機能(入門)」と題して紹介します。

ダウンロード

Eclipseのダウンロード方法は様々なページで紹介されています。例えば、「Eclipse 4.2 のダウンロード,インストール,設定,日本語化,基本操作」(長いので、以下「Javaイントロ」と書きます)には、Eclipseのダウンロード、インストール、簡単な操作方法が書いてあります。こういうページを作ってくれる方、本当にありがたいですね♪

まずは、ダウンロードして、起動。

起動時に少々待たされますが、期待を増大させる時間でもあります。

設定

起動したら、Javaイントロにしたがって設定。好みやコーディング規約にやると思いますが、私の場合、Text Editors設定では、以下の項目にチェックを付けています。

  • Insert spaces for tabs
  • Show line numbers
  • Show whitespace characters


また、文字コード設定はUTF-8にしています。

Tasksビューの表示

実際するときに便利な設定がコレ。Tasksビューの表示です。メニューから「Window」「Show View」「Tasks」と選びます。

すると、画面下部に「Tasks」のタブが表示されるようになります。

コメントに「TODO」と記述した箇所の一覧がこのタブに表示されるので便利。TODOを付けておき、チェックすることで、実装漏れを防ぐことができます。

Outlienのカスタマイズ

もうひとつ、便利で手放せない機能を紹介します。
Outlineはフィールドやメソッドを一覧できる便利なビューですが、ある程度大きなクラスになると、ごちゃごちゃして見づらくなります。
私の場合、Outlineから素早く状況を掴むために、Outlineのビューでは「Sort」「Hide Fields」にチェックを付けています。

これを使うと、デフォルトでは記述順に表示されていたメソッドが、メソッド名でソートされて表示されます。また、フィールドが表示されなくなるため、メソッドのみ参照できるようになります。これにより、Outlineを素早く把握することができます。
フィールドに注目したい場合は、表示するように戻します。

最後に

実は、私が社会人になった頃、まだEclipseはありませんでした。GUIの開発環境はありましたが、Eclipse程便利な機能は揃っていませんでした。そのため、Eclipseが登場した時は「デバッグが10倍速くなる!」と感じました。
今回紹介した便利機能はまだ入口にすぎず、Eclipseには、まだまだ数多くの便利機能が存在します。新人の皆さんは、自分でメニューを触ったり、インターネットで調べたり、周囲の人に聞いたりすることで、(本気で)10倍くらいデバッグが速くなりますよ♪

リフレクションって、どれくらい遅くなるの?

「リフレクションを大量に使うときはキャッシュせよ!」とは良く聞きますが、「キャッシュしたからと言って、速いのか?」という疑問がありました。そこで、検証。リフレクションと、直接のメソッド呼び出しを10億回実行して時間を比較してみました。
メインプログラムは以下の通り。単にsetterを呼び出しているだけです。

package jp.gr.java_conf.snuffkin.sandbox.reflection;

import java.lang.reflect.Method;

public class TestReflectionSpeed {
    public static void main(String[] args) throws Exception {
        SampleEntity target = new SampleEntity();
        Method method = SampleEntity.class.getMethod("setName", String.class);
        
        int call = 1000000000;
        long startTime = System.currentTimeMillis();
        for (int index = 0; index < call; index++) {
            method.invoke(target, "test");
        }
        System.out.println("reflection :time(ms)=" + (System.currentTimeMillis() - startTime));
        
        startTime = System.currentTimeMillis();
        for (int index = 0; index < call; index++) {
            target.setName("test");
        }
        System.out.println("direct call:time(ms)=" + (System.currentTimeMillis() - startTime));
    }
}

呼び出しているエンティティクラスは以下の通り。

package jp.gr.java_conf.snuffkin.sandbox.reflection;

public class SampleEntity {
    private String name;
    public void setName(String name) {
        this.name = name;
    }
}

私が測定に使ったのは、Core2DuoのMac Book Air。いまどきのマシンと比べるとCPU性能は落ちますね。で、結果は以下の通り。

reflection :time(ms)=19054
direct call:time(ms)=44

確かに、直接メソッドを読んだ方が速いです。しかし、10億回をリフレクションを呼んでも19秒。この性能なら、大抵のアプリケーションでリフレクションを使っても性能的に問題なさそうですね。

Netty3からNetty4へのなんちゃって移植

2012/07/07追記
Netty4のAPIはその後更新され、Netty3でのAPIは残していないようです。
そのため、ここに書いた内容は現在では使えませんのでご注意ください。

2013/10/17追記
Netty3からNetty4へのちゃんとしたマイグレーション方法は「How to Migrate Netty 3 to 4 (Netty 番外編) - Taste of Tech Topics」に記載しましたので、こちらをご覧ください。

以前、Nettyのことを書いてから全然続きを書いていませんでした。その間にNettyの開発は進み、Netty3からNetty4に進化しようとしています。Nettyのgithubに行くと、開発中のNetty4のコードがあるので遊んでみました。Netty4では"next-api"と呼ばれている新しいAPIを使っているのですが、ひとまず、以前の書いたソースをNetty3からNetty4に移植してみました。すると、next-apiを使わずに、パッケージ名を変えただけでほとんど動きました。どうやら、以前のAPIも残しているようですね。

echoサンプルくらいなら、以下の2種類の修正だけで、Netty4に対応することができました(ただし、Netty4は開発中なので、APIは今後変わるかもしれません。また、使うAPIによってはNetty4でそのまま使えないかもしれません)。

  1. importするパッケージを"org.jboss.netty"から"io.netty"に変更する
  2. NioClientSocketChannelFactoryのコンストラクタ引数の変更に対応する

サンプルソースは以下の通りです。

  • EchoServer
package jp.gr.java_conf.snuffkin.sandbox.netty_next.echo;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFactory;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPipelineFactory;
import io.netty.channel.Channels;
import io.netty.channel.socket.nio.NioServerSocketChannelFactory;
import io.netty.handler.codec.frame.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.frame.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

/**
 * サーバ側メインクラス
 */
public class EchoServer {

    public static void main(String[] args) {
        ChannelFactory factory = 
            new NioServerSocketChannelFactory( // server
                    Executors.newCachedThreadPool(),
                    Executors.newCachedThreadPool()
                    );
        
        ServerBootstrap bootstrap = new ServerBootstrap(factory);
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() {
                ChannelPipeline pipeline = Channels.pipeline();
                // Downstream(送信)
                pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
                pipeline.addLast("stringEncoder", new StringEncoder());
                // Upstream(受信)
                pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(8192, 0, 4, 0, 4));
                pipeline.addLast("stringDecoder", new StringDecoder());
                // Application Logic Handler
                pipeline.addLast("handler", new EchoServerHandler()); // server
                
                return pipeline;
            }
        });
        
        bootstrap.bind(new InetSocketAddress(9999)); // 9999番ポートでlisten
    }
}
  • EchoServerHandler
package jp.gr.java_conf.snuffkin.sandbox.netty_next.echo;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageEvent;
import io.netty.channel.SimpleChannelHandler;

/**
 * サーバ側アプリケーションロジック
 */
public class EchoServerHandler extends SimpleChannelHandler {
    /**
     * クライアントから電文を受信した際に呼び出されるメソッド
     */
    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent event) {
        String msg = (String) event.getMessage(); // 受信電文を取りだす
        ctx.getChannel().write(msg); // クライアントに送信
    }
}
package jp.gr.java_conf.snuffkin.sandbox.netty_next.echo;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

import io.netty.bootstrap.ClientBootstrap;
import io.netty.channel.ChannelFactory;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPipelineFactory;
import io.netty.channel.Channels;
import io.netty.channel.socket.nio.NioClientSocketChannelFactory;
import io.netty.handler.codec.frame.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.frame.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

/**
 * クライアント側メインクラス
 */
public class EchoClient {

    public static void main(String[] args) {
        ChannelFactory factory =
            new NioClientSocketChannelFactory( // client
                    Executors.newCachedThreadPool() // ★引数変えています
                    );
        
        ClientBootstrap bootstrap = new ClientBootstrap(factory);
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() {
                ChannelPipeline pipeline = Channels.pipeline();
                // Downstream(送信)
                pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
                pipeline.addLast("stringEncoder", new StringEncoder());
                // Upstream(受信)
                pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(8192, 0, 4, 0, 4));
                pipeline.addLast("stringDecoder", new StringDecoder());
                // Application Logic Handler
                pipeline.addLast("handler", new EchoClientHandler()); // client

                return pipeline;
            }
        });
        
        ChannelFuture future = bootstrap.connect(new InetSocketAddress("localhost", 9999)); // 9999番ポートにconnect
        future.getChannel().getCloseFuture().awaitUninterruptibly();
        bootstrap.releaseExternalResources();
    }
}
  • EchoClientHandler
package jp.gr.java_conf.snuffkin.sandbox.netty_next.echo;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelStateEvent;
import io.netty.channel.MessageEvent;
import io.netty.channel.SimpleChannelHandler;

/**
 * クライアント側アプリケーションロジック
 */
public class EchoClientHandler extends SimpleChannelHandler {
    /**
     * サーバに接続した際に呼び出されるメソッド
     */
    @Override
    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent event) {
        ctx.getChannel().write("Hello, World!");
    }
    
    /**
     * サーバから電文を受信した際に呼び出されるメソッド
     */
    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent event) {
        String msg = (String) event.getMessage();
        System.out.println(msg);
    }
}

これだけで、動きました。next-apiを使っていなので、これを移植と言ってはズルイ気がしますが。。。次はもうちょっと真面目に書きます^^