覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。twitter: @yyoshikaw

Javaで外部プロセスを実行する

Java8以上の世の中だと思いますので、外部プロセスを実行する場合はProcessBuilderクラスを使いましょう。

今回は、外部プロセスが出力する標準出力や標準エラー出力の内容は無視して、終了コードだけを取得する例となっています。

Javaで?外部プロセスを実行する場合、よく出る話ですが以下の考慮が必要です。

外部プロセスは標準出力(や標準エラー)に書き込みたいしたいのに、受け側のProcessのInputStreamがいっぱいになってしまいます。
そのため、ストリームから読み出してやらないとバッファーが不足して、書き込み側(外部プロセス)がブロッキング(一時停止)してしまい、
そのプロセスは終了しないことになります。


実行用クラスは以下のような感じになるかと思います。

import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;

public final class CommandExecutor {

    public static int execute(String cmd, List<String> params, long timeoutSec) {
        List<String> cmdAndParams = new LinkedList<>();
        cmdAndParams.add(cmd);
        cmdAndParams.addAll(params);

        return execute(cmdAndParams, timeoutSec);
    }

    public static int execute(String cmd, long timeoutSec) {
        return execute(Arrays.asList(cmd), timeoutSec);
    }

    private static int execute(List<String> cmdAndParams, long timeoutSec) {
        ProcessBuilder builder = new ProcessBuilder(cmdAndParams);
        builder.redirectErrorStream(true);  // 標準エラー出力の内容を標準出力にマージする

        Process process;
        try {
            process = builder.start();
        } catch (IOException e) {
            throw new CommandExecuteFailedException("Command launch failed. [cmd: " + cmdAndParams + "]", e);
        }

        int exitCode;
        try {
            // 標準出力をすべて読み込む
            new Thread(() -> {
                try (InputStream is = process.getInputStream()) {
                    while (is.read() >= 0); 
                } catch (IOException e) {
                    throw new UncheckedIOException(e);
                }
            }).start();

            boolean end = process.waitFor(timeoutSec, TimeUnit.SECONDS);
            if (end) {
                exitCode = process.exitValue();
            } else {
                throw new CommandExecuteFailedException("Command timeout. [CommandPath: " + cmdAndParams + "]");
            }

        } catch (InterruptedException e) {
            throw new CommandExecuteFailedException("Command interrupted. [CommandPath: " + cmdAndParams + "]", e);
        } finally {
            if (process.isAlive()) {
                process.destroy(); // プロセスを強制終了
            }
        }

        return exitCode;
    }

    private CommandExecutor() {
    }
}


独自の例外クラスも一応定義

public final class CommandExecuteFailedException extends RuntimeException {

    public CommandExecuteFailedException(String message) {
        super(message);
    }

    public CommandExecuteFailedException(String message, Throwable cause) {
        super(message, cause);
    }
}


実行例は以下の通りです


存在するコマンドの実行

java -version

■実行用コード

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        System.out.println("Command start [java -version]");
        int exitCode = CommandExecutor.execute("java", Arrays.asList("-version"), 3);

        System.out.printf("Command end. [exitCode: %d]\n", exitCode);
    }
}


■実行結果

Command start [java -version]
Command end. [exitCode: 0]


正常終了しています


存在しないオプションを指定して実行

java -unknown

■実行用コード

(上記と同様でmainで実行していますが、同様の箇所のコードをかなり省略しています)

System.out.println("Command start [java -unknown]");
int exitCode = CommandExecutor.execute("java", Arrays.asList("-unknown"), 3);

System.out.printf("Command end. [exitCode: %d]\n", exitCode);


■実行結果

Command start [java -unknown]
Command end. [exitCode: 1]


exitCode = 1 で異常終了しています


タイムアウトするコマンドを実行

ping 127.0.0.1 -c 100

■実行用コード

タイムアウト時間を3秒にして実行しています

System.out.println("Command start [ping 127.0.0.1 -c 100]");
int exitCode = CommandExecutor.execute("ping", Arrays.asList("127.0.0.1", "-c", "100"), 3);

System.out.printf("Command end. [exitCode: %d]\n", exitCode);


■実行結果

Command start [ping 127.0.0.1 -c 100]
Exception in thread "main" net.yyuki.cmd.CommandExecuteFailedException: Command timeout. [CommandPath: [ping, 127.0.0.1, -c, 100]]
    at net.yyuki.cmd.CommandExecutor.execute(CommandExecutor.java:51)
    at net.yyuki.cmd.CommandExecutor.execute(CommandExecutor.java:18)
    at net.yyuki.cmd.trial.Main3.main(Main3.java:10)


タイムアウトして、CommandExecuteFailedExceptionがスローされています


存在しないマンドを実行

unknown_cmd -h

■実行用コード

存在しないunknown_cmdというコマンドを実行しています

System.out.println("Command start [unknown_cmd -h]");
int exitCode = CommandExecutor.execute("unknown_cmd", Arrays.asList("-h"), 3);

System.out.printf("Command end. [exitCode: %d]\n", exitCode);


■実行結果

Command start [unknown_cmd -h]
Exception in thread "main" net.yyuki.cmd.CommandExecuteFailedException: Command launch failed. [cmd: [unknown_cmd, -h]]
    at net.yyuki.cmd.CommandExecutor.execute(CommandExecutor.java:33)
    at net.yyuki.cmd.CommandExecutor.execute(CommandExecutor.java:18)
    at net.yyuki.cmd.trial.Main5.main(Main5.java:10)
Caused by: java.io.IOException: Cannot run program "unknown_cmd": error=2, No such file or directory
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
    at net.yyuki.cmd.CommandExecutor.execute(CommandExecutor.java:31)
    ... 2 more
Caused by: java.io.IOException: error=2, No such file or directory
    at java.lang.UNIXProcess.forkAndExec(Native Method)
    at java.lang.UNIXProcess.<init>(UNIXProcess.java:247)
    at java.lang.ProcessImpl.start(ProcessImpl.java:134)
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
    ... 3 more


対象のコマンドが存在せず、CommandExecuteFailedExceptionがスローされています


まとめ

ProcessBuilderクラスを利用して外部プロセスを実行してみました

Gson で JSONICの簡単なアダプタを作る

JavaでもJSONを扱わなければならなくなった初期の頃に、JSONICというライブラリのお世話になった方も少なく無いのでは無いでしょうか?

今となっては、jacksonGson 等の他のライブラリを使うのが一般的になっています。


JSONICのページにも以下のように書かれていました。

2018/7/1 JSONIC は、リポジトリを GitHub に移動するとともに今後機能強化が行われることがないメンテナンスモードに移行します。
機能、パフォーマンス共に優れた jackson への移行をおすすめいたします。

なんだか時代を感じます。

というわけで、JSONICを利用しているコードは基本的に、jacksonGson を利用するプログラムに書き換えた方がいいでしょう。

が、そういったプログラム改修が面倒だという場合は、アダプタを作るのも一つのやり方かもしれません。

今回は、JSONICのライブラリを利用していたコードをそのままに、Gsonで処理させるようにしてみます。

log4jのクラスを利用しているコードをのままで、slf4j で処理を実行する log4j-over-slf4j みたいなイメージです。


と言っても、今回はものすごく単純なサンプルですので、JSONICの機能を使い倒していればいるほど動かないと思います。


今回JSON文字列から変換するオブジェクトは以下とします。

import java.util.Arrays;

public final class Person {

    private String name;

    private int age;

    private String[] hobby;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String[] getHobby() {
        return hobby;
    }

    public void setHobby(String[] hobby) {
        this.hobby = hobby;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", hobby=" + Arrays.toString(hobby) +
                '}';
    }
}


JSONICの動きの確認

まず、JSONIC の動きの確認のためにpom.xmlにJSONICライブラリを追記します

<dependency>
        <groupId>net.arnx</groupId>
        <artifactId>jsonic</artifactId>
        <version>1.3.10</version>
</dependency>


実行のためのサンプルコードは以下の通りです。以下2つの処理を行っています

  • Pesonのインスタンスを生成して、JSON文字列化 (encode)
  • JSON文字列からPesonのインスタンス生成 (decode)

■サンプルコード

import net.arnx.jsonic.JSON;

public class JSONICTrial {

    public static void main(String[] args) {
        Person p = new Person();
        p.setName("taro");
        p.setAge(10);
        p.setHobby(new String[] {"Reading", "Travel"});

        // オブジェクトからJSON文字列へ変換
        String json = JSON.encode(p);
        System.out.printf("%s -> >>encode>> -> %s\n\n", p, json);


        // JSON文字列からオブジェクトへ変換
        Person p2 = JSON.decode(json, Person.class);
        System.out.printf("%s -> >>decode>> -> %s\n\n", json, p2);
    }
}


実行結果は以下の通りです。

■実行結果

Person{name='taro', age=10, hobby=[Reading, Travel]} -> >>encode>> -> {"age":10,"hobby":["Reading","Travel"],"name":"taro"}

{"age":10,"hobby":["Reading","Travel"],"name":"taro"} -> >>decode>> -> Person{name='taro', age=10, hobby=[Reading, Travel]}


JSONICのアダプタと動きの確認

JSONICを利用したコードをGson で処理させるために、pom.xmlにGsonの依存関係を追記します

<dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.5</version>
</dependency>

その上で、pom.xmlからJSONICライブラリの記述を除外します


JSONICを利用したコードをGson で処理させるために以下のコードを記述します

package net.arnx.jsonic;

import com.google.gson.Gson;

public final class JSON {
    private static final Gson gson = new Gson();

    public static String encode(Object o) {
        return gson.toJson(o);
    }

    public static <T> T decode(String json, Class<T> type) {
        return gson.fromJson(json, type);
    }
}


この状態で元のJSONICTrialを実行すると以下のようになります。

■実行結果

Person{name='taro', age=10, hobby=[Reading, Travel]} -> >>encode>> -> {"name":"taro","age":10,"hobby":["Reading","Travel"]}

{"name":"taro","age":10,"hobby":["Reading","Travel"]} -> >>decode>> -> Person{name='taro', age=10, hobby=[Reading, Travel]}

JSON文字列の項目の並び順が微妙に違っていますが、基本的に同じ結果が得られています。


まとめ

今回は、JSONICの超基本的なAPIのみをアダプタとして作成しましたが、それにより一応元のプログラムは改修なしでGsonで処理させて動作することがわかりました。



関連リンク

Gson - JsonWriterでインデント形式を変えてファイル出力してみる

以前JSON形式のデータをJavaで扱うためのGsonライブラリについて使い方を紹介しました。

今回はGsonライブラリのGsonオブジェクトを使わずにJSONファイルへの出力を行ってみます。
その際にインデントの形式をいくつか変えて出力します。

今回出力するJSONファイルの内容は以下のようなものとします

{
 "files": [
  {
   "name": "data-1.txt",
   "size": 1024,
   "type": "file",
   "update.time": 1538835662719
  },
  {
   "name": "data-2.txt",
   "size": 2048,
   "type": "file",
   "update.time": 1538835662719
  },
 ・・・繰り返し
 ]
}


インデントなしで出力

サンプルコードは以下の通りです。JsonWriter.setIndent メソッドを実行していないのが着目点になります。


■サンプルコード

import com.google.gson.stream.JsonWriter;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class GsonTrial1 {

    public static void main(String[] args) throws Exception {
        write1(new File("sample1.json"));
    }

    private static void write1(File file) throws IOException {
        try (JsonWriter writer = new JsonWriter(new FileWriter(file))) {

            writer.beginObject();
            writer.name("files");
            writer.beginArray();

            for (int i = 1; i <= 10; i++) {
                writer.beginObject();
                writer.name("name").value("data-" + i + ".txt");
                writer.name("size").value(1024 * i);
                writer.name("type").value("file");
                writer.name("update.time").value(System.currentTimeMillis() + i);
                writer.endObject();
            }
            writer.endArray();
            writer.endObject();
        }
    }
}


■実行結果(ファイルへの出力内容)

{"files":[{"name":"data-1.txt","size":1024,"type":"file","update.time":1538835662718},{"name":"data-2.txt","size":2048,"type":"file","update.time":1538835662718},{"name":"data-3.txt","size":3072,"type":"file","update.time":1538835662718},{"name":"data-4.txt","size":4096,"type":"file","update.time":1538835662718},{"name":"data-5.txt","size":5120,"type":"file","update.time":1538835662718},{"name":"data-6.txt","size":6144,"type":"file","update.time":1538835662718},{"name":"data-7.txt","size":7168,"type":"file","update.time":1538835662718},{"name":"data-8.txt","size":8192,"type":"file","update.time":1538835662719},{"name":"data-9.txt","size":9216,"type":"file","update.time":1538835662719},{"name":"data-10.txt","size":10240,"type":"file","update.time":1538835662719}]}

JSONファイルとしての必要な形式は当然満たしていますが、人間が読むにはちょっと辛いかもしれません。


インデントありで出力

上記のサンプルでは出力されるJSONファイルの内容が人間にとって読みにくいので、今度は読みやすいようにインデントして出力してみます。


サンプルコードは以下の通りです。先ほどのサンプルとは異なりJsonWriter.setIndent メソッドを実行してインデントするようにしています。


■サンプルコード

import com.google.gson.stream.JsonWriter;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class GsonTrial2 {

    public static void main(String[] args) throws Exception {
        write2(new File("sample2.json"));
    }

    private static void write2(File file) throws IOException {
        try (JsonWriter writer = new JsonWriter(new FileWriter(file))) {
            writer.setIndent(" ");  // インデントするようにした

            writer.beginObject();
            writer.name("files");
            writer.beginArray();

            for (int i = 1; i <= 10; i++) {
                writer.beginObject();
                writer.name("name").value("data-" + i + ".txt");
                writer.name("size").value(1024 * i);
                writer.name("type").value("file");
                writer.name("update.time").value(System.currentTimeMillis() + i);
                writer.endObject();
            }
            writer.endArray();
            writer.endObject();
        }
    }
}


■実行結果(ファイルへの出力内容)

{
 "files": [
  {
   "name": "data-1.txt",
   "size": 1024,
   "type": "file",
   "update.time": 1538836735394
  },
  {
   "name": "data-2.txt",
   "size": 2048,
   "type": "file",
   "update.time": 1538836735395
  },
  {
   "name": "data-3.txt",
   "size": 3072,
   "type": "file",
   "update.time": 1538836735397
  },
  {
   "name": "data-4.txt",
   "size": 4096,
   "type": "file",
   "update.time": 1538836735398
  },
  {
   "name": "data-5.txt",
   "size": 5120,
   "type": "file",
   "update.time": 1538836735399
  },
  {
   "name": "data-6.txt",
   "size": 6144,
   "type": "file",
   "update.time": 1538836735400
  },
  {
   "name": "data-7.txt",
   "size": 7168,
   "type": "file",
   "update.time": 1538836735401
  },
  {
   "name": "data-8.txt",
   "size": 8192,
   "type": "file",
   "update.time": 1538836735402
  },
  {
   "name": "data-9.txt",
   "size": 9216,
   "type": "file",
   "update.time": 1538836735404
  },
  {
   "name": "data-10.txt",
   "size": 10240,
   "type": "file",
   "update.time": 1538836735405
  }
 ]
}

JSONとしての内容に違いはありませんが、最初のサンプルに比べて人間が読みやすい形式になりました。


インデントありで出力(少しファイルサイズを気にする)

先ほどの実行サンプルで出力されるJSONファイルの内容は人間の目には見やすくなったのですが、
スペースや改行が入りまくるので、List内のデータ量が増えると出力したファイルサイズかなり大きくなってしまいます。

ファイルサイズをある程度抑えつつ、人間の目にも見やすい感じで出力してみます。


サンプルコードは以下の通りです。先ほどのサンプルとは異なりJsonWriter.setIndent メソッドを繰り返し処理の中で複数回実行してインデントをONにしたりOFFにしたりしています。


■サンプルコード

import com.google.gson.stream.JsonWriter;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class GsonTrial2 {

    public static void main(String[] args) throws Exception {
        write3(new File("sample3.json"));
    }

    private static void write3(File file) throws IOException {
        try (JsonWriter writer = new JsonWriter(new FileWriter(file))) {
            writer.setIndent(" ");  // インデントON

            writer.beginObject();
            writer.name("files");
            writer.beginArray();

            for (int i = 1; i < 10; i++) {
                writer.beginObject();
                writer.setIndent("");    // インデントOFF
                writer.name("name").value("data-" + i + ".txt");
                writer.name("size").value(1024 * i);
                writer.name("type").value("file");
                writer.name("update.time").value(System.currentTimeMillis() + i);
                writer.endObject();
                writer.setIndent(" ");   // インデントON
            }
            writer.endArray();
            writer.endObject();
        }
    }


■実行結果(ファイルへの出力内容)

{
 "files": [
  {"name":"data-1.txt","size":1024,"type":"file","update.time":1538837153533},
  {"name":"data-2.txt","size":2048,"type":"file","update.time":1538837153534},
  {"name":"data-3.txt","size":3072,"type":"file","update.time":1538837153535},
  {"name":"data-4.txt","size":4096,"type":"file","update.time":1538837153536},
  {"name":"data-5.txt","size":5120,"type":"file","update.time":1538837153537},
  {"name":"data-6.txt","size":6144,"type":"file","update.time":1538837153538},
  {"name":"data-7.txt","size":7168,"type":"file","update.time":1538837153540},
  {"name":"data-8.txt","size":8192,"type":"file","update.time":1538837153541},
  {"name":"data-9.txt","size":9216,"type":"file","update.time":1538837153542}
 ]
}

人間が読みやすい形式を保ちつつ、ファイルサイズをある程度抑えた出力になりました、


まとめ

GsonJsonWriter.setIndentをうまく利用することで、出力するJSONののインデントをある程度制御することができました。



関連エントリ

Java 11リリースに関するメモ

先日、Java 11が正式リリースされました。

ご存知の通りですが、本バージョンからOracle JDKが有償となりました。

その辺についての自分用のメモです。(不正確だったり間違っている内容もあるかもしれません)


概要

Java 11リリースに関連する内容は以下の通りです

  • Java 9から半年ごとにメジャーバージョンが上がるリリースがされていたが、(Oracle)のJava 11は長期サポート(LTS:Long Term Support)対象のバージョンになる
  • Oracleでは、LTS対象だったJava 8のサポートは2019年1月に終了する
  • 32bit版のバイナリは提供されない(?)
  • JavaFXがJDKから削除された(分離された)
  • Java Web Startが削除された
  • sun.misc.Unsafe(の一部?)が削除された


機能的なリリース内容などは以下のリリースノートを参照ください。

JDK 11 Release Notes


Oracle JDK

多くの人、多くのシステムで利用されていたのがOracleのJavaだと思います。

本バージョンから有償となりましたが、Oracleのサイトから無料でダウンロードできてしまいます。
が、ライセンスが変更になっています。
Oracle Java SE License

商用環境等で利用する場合、金を払う必要があります。
開発、テスト、プロトタイプ作成、デモを目的としていて業務、商用又は本番利用を目的として使用しない場合は無償利用して良いようです。

ダウンロードする場合は以下から実施ください。

Java SE Development Kit 11- - Downloads


OpenJDK

Javaの開発コミュニティで、Oracleがメインスポンサーとして開発が行われています。ほぼすべてのJavaの中心となります。

(もともとLTSの話が出ていましたが、結局)LTSに対応した3年間のバグフィックスやセキュリティパッチの提供予定が表明されていません。

ダウンロードは以下から実施ください。(Oracleがビルドしたバイナリを提供しています)

JDK 11 GA Release


AdoptOpenJDK

自分自身、最近まで存在すら知らなかったです。。。

OpenJDKのビルドを提供するコミュニティで、MicrosoftやIBMなどがメインスポンサーに名を連ねています。

無償で利用できますし、LTSに関して4年間のサポートを表明しています。

Support | AdoptOpenJDK - Open source, prebuilt OpenJDK binaries


他でもよく書かれていますが、無償利用したい場合はこのJDKが最有力候補かもしれません。


現時点(2018/9/29)では、リリースされていませんが、以下リンク先等からダウンロードできるようになると思われます。

Archive | AdoptOpenJDK - Open source, prebuilt OpenJDK binaries


他のJava

RedHat等の各種LinuxディストリビューションやAzul SystemsなどもOpenJDKのビルドバイナリを提供しています。


現場でよく聞く声

Java 11リリースに関して、Java(Oracle JDK)を使ってサービスを提供している側やそのシステムを利用しているユーザからよく聞く声として以下のようなものがあります。

  • これまでも、Javaに関しては別にOracleのサポートは受けたことがない。そのため、OpenJDKの利用でも問題ない。
    が、大きな企業の正式な後ろ盾が無いのが気になる。
  • 脆弱性の対応がなされない古いバージョンを使い続ける選択肢は基本的に考えていない。
  • 有償版のOracle JDKを利用してもいいが、その費用はサービス提供者が支払うのか?ユーザが払うのか?が課題となっている
  • 一部APIが削除されているので、Java 8以下で動作させていたアプリが、Java 11では動かないケースが結構ある。
  • JavaでGUIアプリ作る場合は結局何で作ればいいの?(JavaFXが分離されてしまった。Swingで作るのが良いの?)


まとめ

まとめというまとめは私にできませんが、Java 11はJavaにとっての大きな節目になるのかも?とは思います。



関連リンク

「悪いヤツほど出世する」

「悪いヤツほど出世する」。読んだのは結構前ですが面白かったので、その時自分が気になった部分などをメモするためのエントリです

悪いヤツほど出世する

悪いヤツほど出世する

なかなか過激なタイトルですが、一考に値するような内容が書かれています。
正直、納得せざるを得ない部分も多くあります。

本の紹介は以下のように書かれています。

ジョブズもゲイツもウェルチも、「いい人」ではなかった! 

リーダーは謙虚であれ、誠実であれ、そして部下への思いやりを持て。
リーダーシップに関する教えでは、よくこうした美しい主張が説かれ、一般的にも優れたリーダーはこのような資質を備えるべきだと思われているでしょう。

しかし、現実のデータを分析すると、実は多くの成功しているリーダーはこうした資質を備えていません。
スタンフォード大学ビジネススクールの教授が、巷にはびこる「リーダー論」のウソを暴き、
組織の目標を達成して職場環境をよくするためには何が効果的なのか、
また悪しき上司の犠牲にならないためにはどうしたらよいのかを、豊富なデータと実例から解き明かします。

章立ては以下のようになっています。

  • 序章: リーダー教育は、こうして失敗した
  • 第1章: 「リーダー神話」は、百害あって一利なし
  • 第2章: 謙虚 ― そもそも控えめなリーダーはいるのか?
  • 第3章: 自分らしさ ― 「本物のリーダー」への過信と誤解
  • 第4章: 誠実 ― リーダーは真実を語るべきか?(そして語っているか?)
  • 第5章: 信頼 ― 上司を信じてよいものか
  • 第6章: 思いやり ― リーダーは最後に食べる?
  • 第7章: 自分の身は自分で守れ
  • 第8章: リーダー神話を捨て、真実に耐える

自分自身も リーダーシップ研修 とよばれるようなものを受講せざるを得ない時があるのですが、
その研修を受けた時に感じた違和感を補足してくれるような感じの内容になっています。

もしも気になって内容読もうと思われる方は先のリンクのものではなく、現在は文庫本が出ているので、そっちを買ったほうが割安です。


本書籍内で、私が気になった部分の抜粋を一部メモしておきます。(括弧書きの部分はわかりやすくするため、私が付け足しています)

  • リーダーシップ教育産業は失敗した、ということだ。彼らの情熱は認めるとしても、効果があったという証拠はあまりに乏しい。
    それどころか数々のプログラムは、世間が思う以上に無益であり、むしろ有害である。

  • (リーダーシップ教育産業の)大きな問題点として一つ考えられるのは、今日のリーダーシップ開発や研修で、英雄的なリーダーや卓越した企業のか輝かしいサクセスストーリーが頻繁に受講者に語られることだ。
    その手の物語は、一時的に気分を高揚させ士気を高める効果があっても、現実の職場には活かせないことが多い。

  • 自己利益の追求が当人のためだけではなく広く社会に資することは、アダム・スミスの時代から現代にいたるまで、あらゆる経済理論が主張するところである。
    それ以外の経済制度、たとえば利他的で慈愛あふれる父親のような人物に生産や配分や雇用を委ねるといったやり方は、控えめに言っても危険が多い。

  • リーダーシップという概念は、組織の現実に比して不釣り合いに高い地位と重要性を与えられることになった。
    社会がリーダーシップをひどく重視するようになった結果、この概念は学問的に裏付けのないような光輝を帯びるようになったのである

  • 人材関連で45年の実績を誇るDDIは、広範な調査に基づく調査を毎年発表しているが・・・リーダーシップ開発の成果が上がっている証拠は見当たらない という。・・・白書によれば、回答者の半分を上回る55%が上司を理由に会社を辞めたいと答えており、39%が実際に辞めているのである。

  • リーダーの行動と職場の結果の間に強い因果関係があるとの前提に立っているにもかかわらず、実際にリーダーは(リーダーシップ研修で)教わったことを実行しているのかは、ほとんど実態調査が行われていない。

  • 大量のプログラムやセミナーを提供して助言をするだけで、実践されたかどうか、実態が改善されたかどうか、改善されていないとすればそれはなぜか、といったことを突き止める努力もしていない。
    彼らは、リーダーはこうあるべきだとか、ものごとはこうでなければならないといった規範的なことにこだわりすぎており、実態はどうなっていて、それはなぜか、という基本的な問いを発していないのである。
    リーダーと職場の実態が計測されていない限り、またリーダーがが自らの行動の改善とその結果に責任を問われない限り、状況は変わらないだろう。

  • リーダーシップ教育産業には「参入障壁」がまったくない

  • リーダーシップ・コーチングやコンサルティングで花形になるのに、知識は無用なのである。・・・いまや彼らの目的は、悩めるリーダーや職場の解決策として、目にも耳にも心地よいエンターテイメントを提供することなのである。

  • (リーダーシップ研修を受講しても)職場の状況がいっこうに改善されないのも無理はない。リーダーシップ教育の直接の目的であるはずの職場の満足度を計測せずに、プログラム参加者の、つまり「お客さま」の満足度を計測しているのである。
    プログラムにご満足していただけましたか、楽しんでいただけましたか、と。

  • まちがったものを計測するのは、何も計測しないより悪いことが多い。なぜなら計測したものに囚われるようになるからだ。
    どれだけ多くの人が楽しんだかを計測し、それがプログラム(あるいは本、講演、セミナー)の成功の指標になるとすれば、当然ながら参加者をより楽しく、より心地よくさせようということになる。
    端的に言って、プログラムが楽しいかどうかを計測していたら、参加者はより楽しくはなるだろうが、態度や行動が変化することは期待できない。

  • 企業文化を大切にせよとか、人材こそが最重要資産である、といったご高説はよく耳にするが、実際の行動が伴われるのは稀だ。

  • 何かの病気をたまたまうまく治せたからといって、専門的な教育を受けていない人がその治療法を人々に宣伝するなどあり得ない。
    だがこのあり得ないことが、リーダーシップの分野では起きている。リーダーとして華々しい成功を収めたとか英雄的な行為をしたといったエピソードの持ち主なら、誰でも堂々とリーダーシップを教えることができる。

  • 職場をよりよくし、部下の意欲や満足度や生産性を高めたいと本気で思っているなら、あるいはリーダーとしてのクオリティを高め、キャリアアップをめざしたいなら、感動体験に用はない。
    必要なのは、事実であり、データであり、アイデアだ。
    激励や応援はスポーツの試合には役に立っても職場やキャリアの問題解決にはならない。

  • 人間はうまくいったことだけを覚えていて、自分にとって都合の悪いことは忘れがちである。

  • 「失敗から学べ」という忠告は、さかんにいわれるがほとんど実行されないものの一つと言ってよい。

  • ある経営学の論文では、「自然界においても実業界においても、失敗は最終的な成功につながると言ってよい。生態系では、老化した生命体が死ぬことによって、活発な成長がもたらされる。ビジネスの世界では、非効率な活動を排除することが富の想像につながる」と指摘されている。

  • ジャーカー・デンレルが行なった調査によると、卓越したリーダーのスキルとパフォーマンスの相関関係は、多くの場合にきわめて弱いという。
    これは卓越したリーダーの業績は、幸運や偶発的な要素に左右される部分が大きいからだ。安定して堅実なパフォーマンスを示すが抜きん出て目立つわけでもないという人たちからこそ、学べることが多いとデンレルは主張する。
    なぜならこうした人たちのパフォーマンスは、偶然の産物ではなく、ほんとうの能力や行動の結果である可能性が高いからだ。だから、こうした人たちの行動を分析するほうが、よほど役に立つという。

  • 消費者が見てくれだけではなく、高品質で安全で信頼性の高い自動車を求めて初めて、自動車メーカーはその声に応える。・・・リーダーシップ教育の受け手が、感動を求めるのをやめ、信頼できるデータや知見を求めるようになって初めて、教育の質は上がり、職場をよりよくできるリーダーが育つようになるだろう。

  • あなたがリーダーに選ばれたいなら、最低でも、選ぶ側があなたの存在に気づいていなければならない。
    記憶に残らないような人間は絶対に選ばれない。覚えていない人をどうして選べるだろうか。マーケティング戦略で単純接触効果が重要視されるのはこのためだ。
    人間は、見慣れているもの、よく知っているもの、記憶に残るものを選ぶのであり、これが広告効果を高めるイロハである。リーダーシップについても同じことが言える。人に知られていること、ブランドを確立することが、要するに目立つことは役に立つのである。

  • 自分の気持ちに忠実に振舞うことは、むしろリーダーが最もやってはならないことの一つである。リーダーはその状況で求められる通りに、周囲の人が期待する通りに、ふるまわなければならない。

  • 社会学者のメルヴィン・コーンとカルミ・スクーラーは、・・・調査を行なった結果、性格は職業選択に影響を及ぼすが、いったんある職業を選んだら、今度は性格が職業や仕事から影響を受けることが確かめられた。
    性格のように根本的なものまで職業から影響を受けるとなれば、真の自分などというものは意味をなさないことになる。要は環境に応じて自己は変わるということだ。