覚えたら書く

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

「仕事ごっこ ~その“あたりまえ”、いまどき必要ですか?」

「仕事ごっこ ~その“あたりまえ”、いまどき必要ですか?」 を読んでみました。

仕事ごっこ ~その“あたりまえ

仕事ごっこ ~その“あたりまえ"、いまどき必要ですか?


内容紹介は以下のようになっています

「郵送」「印刷して配布」
「とりあえず打ち合わせ」
「手書き」「メールを送ったら電話で確認」「押印」
「メール添付で圧縮してパスワードつけて、パスワードは別送」
「ひたすらテレアポ」「とにかく相見積り、コンペ」
「年末年始の挨拶や表敬訪問」「スーツ&ネクタイ」「ダイバーシティごっこ」

ちょっと待って、それってホントに必要ですか?

仕事のスピードを遅くし、時間をムダにし、成長機会を奪い、社外の人とのコラボレーションを邪魔し、
優秀な人を遠ざける慣習やルール――それが、“仕事ごっこ"。

これまでの常識を、シニカルなものがたり+ツッコミで、笑い飛ばしながらアップデート! 


この本では冒頭で、仕事ごっこ を以下のように定義しています。

  • 生まれた当初は合理性があったものの、時代や環境や価値観の変化、および技術の進化にともない、生産性やモチベーションの足をひっぱる厄介者と化した仕事や慣習。
  • コラボレーション、ひいてその組織とそこで働く人の剣山な成長を邪魔する形骸化した仕事や慣習。あるいは、仕事のための仕事。


冒頭では、さらに以下のようにも書かれています。

仕事は生きものです。生まれた当初は意味があった。しかし、時代の変化、法制度の変化、テクノロジーの変化、働く人たちやお客さんの価値観の変化・・・さまざまな変化の中で、やがて陳腐化し、時代遅れになります。
そうして、いつの間にか私たちの足をひっぱる厄介者になってしまっているのです。
仕事は生きもの。だからこそ、いったん立ち止まり、正しくアップデート(最新化)していかなければなりません。


この後、各章で、特に大企業でありがちな 仕事ごっこ の事例が紹介されています。

よく分かるなーと思える事例もあれば、まだそんなことしてるの?とさえ思う事例もあります。
どれもこれも、当初は何らかの意味があったのでしょうが、今となっては仕事の生産性を落とすだけのものと化しているものがほとんどです。


薄い本で内容も平易なので、すぐ読み終わることができます。


ただし、難しいなーと思ったのが、
この本をもっとも読んでほしい上級の役職の人ほど、この本を手に取ることはないだろうということです。

若手の方が読んで、内容に納得し自分より下の世代には 仕事ごっこ が残らないように努力するしかないのかな・・・
と、なかなか難しさも感じました。

「社会は変えられる: 世界が憧れる日本へ」

「社会は変えられる: 世界が憧れる日本へ」
たまたまこの本を知る機会があり、読んでみました。

社会は変えられる: 世界が憧れる日本へ

社会は変えられる: 世界が憧れる日本へ


内容紹介は以下のようになっています

超高齢社会を迎え、医療費・介護費の膨張には歯止めがかからず、今や世界に冠たる国民皆保険制度は風前の灯火。
ところが医療関係者や製薬企業などの“専門家"は、古い制度や体制に守られ、同時に縛られ、「沈みゆく豪華客船」の中での席取り合戦に終始するばかり。
この苦境を乗り切るため、現役官僚の著者は、社会・経済システムの見直しによる「生涯現役社会」の創設を説く。
社会全体が変わる中で初めて持続可能な社会保障制度の構築が可能になるという。
前途多難に違いないが、関係者がより広い視点から問題を捉えて行動することができれば、
誰一人切り捨てることなく国民皆保険制度を維持する道が見えてくると主張する。
著者は実際にこれまでも、業界内では「不可能」と考えられていた数々の課題に、“部外者"の視点から切り込み、改革を成し遂げてきた。
その経験から、絶望するのは、まだ早いと説く。著者が思い描くのは、次世代に残すべきこの国の未来であり、
世界が羨望と畏敬の念を持って見つめる「憧れの国」日本の姿だ。


目次は以下の通りです

  • 第一章: 問題の本質を問い直す
  • 第二章: 時代に合わなくなった社会保障制度
  • 第三章: 社会は変えられる! ー 時代に合わない「制度」、業界の「常識」への挑戦
  • 第四章: 世界が憧れる日本へ


以下は、導入となっている「はじめに」の部分からの一部抜粋です

先が見えない難しい状況に陥った時に、私たちは往々にしてこれまで通りのやり方を押し通そうとするか、
「仕方がない」と言ってなにもしないことを正当化してしまうものです。
ところが、一歩引いてより広い視座から全体を俯瞰できるかどうかで、その後の展開は大きく変わります。
対応策が見つからなかった課題でも、違った視点から眺めることで、思いがけないヒントが見つかるものです。
現在、日本の社会保障制度は聞き的な状況にあります。
・・・なかでも「年金」の問題は、将来自分が受け取るお金の話ですから、不安に感じる人も多いでしょう。
・・・実は「年金」よりも遥かに深刻な問題を抱えているのが、日本の医療を支える「国民皆保険制度」です。
誰もが当たり前のように利用している公的医療保険が危機的な状況にあります。
・・・

これら含めて日本の現在の医療に関わる制度を、一度乗船すればいつでも自由に最高の食事などを楽しむことができて目的地まで運んでくれる「豪華客船」に例えています。
ただし、この「豪華客船」は今のままでは沈みゆくことがほぼ確実です。
これは、この筆者が指摘しているだけではなく、多くの場面で課題として上がっており、間違いないことです。

筆者は、今一度日本の医療制度の問題点を整理して、どう対策を打つかというよりも、社会の変化に対してどう考え方や構造を変えるべきかといったところを主張しています。

特に、発症した病気を「治す」医療から「予防」や「管理」を基本とする医療へ転換する という主張は完全に同意します。


ただ、日本の医療制度の問題に対して、あまりに大きな変革が必要となるため、いくら主張されても本当にそんなことが可能なのかと思えてしまいます。
しかし、筆者は官僚としてこれまで多くの無理だとしか思えない課題に取り組み、なんとか解決へ導いてきた事例を三章で述べています。
正直、この章で少ない文章にまとめて書かれていますが、
筆者がいくつものとんでもない苦難へ立ち向い、ギリギリのところまで努力・実行することを諦めず、解決へ導いてきた話は驚きしかありません。

三章の内容を読んでいくつもの難題を解決したこの筆者の主張であれば、医療に関する各種変革に対する話も可能性はゼロではないと感じました。
そしてこの筆者が警鐘を鳴らす問題であるからこそ、日本の医療に関する問題が本当に深刻で、タイムリミットが迫っているとも思えました。


この本を読むべきターゲットは、基本的に日本人全員だと思います。
おおげさな言い方かもしれませんが、現代の日本人がこの筆者の主張を一旦理解することが重要な気がします。
(もちろん、単純な賛成だけではなく批判も出てくると思いますが、とにかくこの本で分かりやすく書かれている現在の日本の課題を理解すべきだと思います)

Kotlin - 簡単なラムダ式を試す

ラムダ式(lambda exoression)または単にラムダ(lambda)とは、本質的には他の関数に渡すことが可能なコードの断片です。
ラムダを利用することで、共通のコード構造を抜き出してライブラリ関数へ渡すこことが可能です。
Kotlin の標準ライブラリはラムダを多用していて、ラムダの最も一般的な利用用途はコレクションの操作です。


以下でKotlinのコードで簡単なコレクションの操作を行ってみます。

data class Product(val name: String, val price: Int)

上記クラスのインスタンスを複数詰め込んだリスト内から最も高い価格(price)のものを見つけるという処理を行います。

サンプルコードで対象のリストは以下のものとします

val products = listOf(Product("A", 10), Product("B", 1), Product("C", 1000))


命令的に、この処理を素直に記述すると以下のようになります。

fun findHighestProduct(products: List<Product>): Product? {
    var maxPrice = 0
    var highestProduct: Product? = null

    for (product in products) {
        if (product.price > maxPrice) {
            maxPrice = product.price
            highestProduct = product
        }
    }

    return highestProduct
}

実行コードは以下のよになります

val products = listOf(Product("A", 10), Product("B", 1), Product("C", 1000))
val highestProduct1 = findHighestProduct(products)  // -> Product(name=C, price=1000)


ラムダ式

Kotlin ではコレクションに対して maxBy 関数を利用することが可能です。
引数には、最大要素を見つけるために比較する値を指定する関数を指定する必要があります。

以下のように記述できます。波括弧内のコードはラムダ式であり、関数の引数として渡します。

val highestProduct = products.maxBy({p: Product -> p.price})

この記述はもっと簡単な記述にできます。
Kotlin では構文規約でラムダ式が関数呼び出しの最終引数であれば括弧の外に移動することが可能です。
この規約を利用すると以下のように記述できます

val highestProduct = products.maxBy() {p: Product -> p.price}

ラムダが関数の唯一の引数であれば、関数呼び出しから空の括弧を取り除いて記述できます。そうすると以下のようになります。

val highestProduct = products.maxBy {p: Product -> p.price}

上記3つの構文は同じことを意味しています。


ラムダの引数の型を推論できる場合は、明示的な指定は不要です。maxBy関数では、その引数の型は常にコレクションの要素の型と同じです。
そのため以下のように型を省いて記述することもできます。

val highestProduct = products.maxBy {p -> p.price}


ちなみにさらなる短絡構文で it を利用して以下のように記述することもできます

val highestProduct = products.maxBy { it.price }

it を用いてコレクション要素を引数として受け取っています。


今回比較する値は price であり、この値は price プロパティに保持されています。
ラムダが単に関数やプロパティを呼び出すだけの場合は、ラムダはメンバ参照を用いて記述することも可能です。

val highestProduct = products.maxBy(Product::price)


まとめ

今回は、Kotlinにおけるコレクションの簡単な操作をラムダ式を使って試してみました。

Kotlin - オブジェクト式

Kotlin の object キーワードは、無名オブジェクト(anonymous object)の宣言のためにも使用できます。
無名オブジェクト は Javaにおける無名内部クラスを置き換えるものとなります。

Javaで無名内部クラスの典型的な利用シーンというと、イベントリストが必要となるケースがあります。

例えば以下のようなJavaのコードがあったとした場合(import 等もろもろ省略)

JWindow window = new JWindow();
window.addMouseListener(new MouseAdapter() {
    @Override
    public void mouseClicked(MouseEvent e) {
        System.out.println("Mouse Clicked");
    }

    @Override
    public void mousePressed(MouseEvent e) {
        System.out.println("Mouse Pressed");
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        System.out.println("Mouse Released");
    }
});

上記コードは Kotlin ではオブジェクト式で以下のように記述できます。

val window = JWindow()
window.addMouseListener(
    object : MouseAdapter() {
        override fun mouseClicked(e: MouseEvent) {
            println("Mouse Clicked")
        }

        override fun mousePressed(e: MouseEvent) {
            println("Mouse Pressed")
        }

        override fun mouseReleased(e: MouseEvent) {
            println("Mouse Released")
        }
    }
)

オブジェクトの名前を省略しているという点をを除いて、オブジェクト宣言と同じです。
オブジェクト式はクラスを宣言し、そのクラスのインスンスを生成しています。


Javaの無名クラスと同様にオブジェクト式の中のコードは、それが生成された関数内の変数を参照することができます。
しかし、Javaとは違って、その変数がfinalでなければならないという制約はありません。
そのため、オブジェクト式の中から変数の値を変更することも可能です。

以下のようなコードを書くことも可能です

var count = 0
val window = JWindow()
window.addMouseListener(
    object : MouseAdapter() {
        override fun mouseClicked(e: MouseEvent) {
            println("Mouse Clicked")
            count++
        }

        override fun mousePressed(e: MouseEvent) {
            println("Mouse Pressed")
            count++
        }

        override fun mouseReleased(e: MouseEvent) {
            println("Mouse Released")
            count++
        }
    }
)


まとめ

オブジェクト式により Java の無名内部クラスを置き換えることができることがわかりました。

Kotolin - コンパニオンオブジェクト 2

Kotlin のコンパニオンオブジェクトは、クラス内に宣言された通常のオブジェクトであり、
名前を付けたり、インターフェースを実装したり、拡張関数やプロパティを持つこともできます。


コンパニオンオブジェクトに名前を付ける

前回のエントリですでにやってやってますが、コンパニオンオブジェクトに名前を付けることが可能です。

import com.google.gson.Gson

class Person(val name: String, val age: Int) {
    // 名前付きのコンパニオンオブジェクトの宣言
    companion object Decoder {
        fun fromJSON(jsonStr: String): Person {
            return Gson().fromJson(jsonStr, Person::class.java)
        }
    }
}

呼び出し側のコードは以下の通りで、コンパニオンオブジェクトの名前を明示することも省略することも可能です。

// コンパニオンオブジェクトの名前を指定して関数を呼び出せる
val p1 = Person.Decoder.fromJSON("""{"name": "Kotlin Taro", "age": 32}""")
println("${p1.name} is ${p1.age} years old.")  // -> Kotlin Taro is 32 years old.

// コンパニオンオブジェクトの名前を省略することもできる
val p2 = Person.fromJSON("""{"name": "Java Taro", "age": 39}""")
println("${p2.name} is ${p2.age} years old.")  // -> Java Taro is 39 years old.


コンパニオンオブジェクトでインターフェースを実装する

他のオブジェクト宣言と同じくコンパニオンオブジェクトはインターフェースを実装できます。
インターフェースを実装しているオブジェクトのインスタンスとして、そのオブジェクトを含むクラスの名前を使用できます。

JSONFactory というインターフェースを介してオブジェクトが生成されるものとする場合、
以下のようなサンプルコードを書くことができます。

import com.google.gson.Gson

interface JSONFactory<T> {
    fun fromJSON(jsonStr: String): T
}

class Person(val name: String, val age: Int) {
    // 名前付きのコンパニオンオブジェクトの宣言
    companion object : JSONFactory<Person> {
        override fun fromJSON(jsonStr: String): Person {
            return Gson().fromJson(jsonStr, Person::class.java)
        }
    }
}


JSONFactoryを引数に取る関数を定義し多とした場合、
その関数を呼び出す場合には、JSONFactoryをコンパニオンオブジェクトが実装しているので Person オブジェクトを引数に渡すことが可能です。

fun <T> loadFromJSON(jsonStr: String, factory: JSONFactory<T>): T {
    return factory.fromJSON(jsonStr)
}

fun main() {
    // JSONFactoryインターフェースの
    val p1 = loadFromJSON("""{"name": "Java Taro", "age": 45}""", Person) // コンパニオンオブジェクトのインスタンスを関数に渡す
    println("${p1.name} is ${p1.age} years old.")
}


コンパニオンオブジェクトの拡張関数

クラスがコンパニオンオブジェクトを持っていれば、コンパニオンオブジェクトに対して拡張関数を定義することが実現できます。
例えば ClazzA がコンパニオンオブジェクトを持つ時、ClazzA.Companion に対する拡張関数 function を定義したと仮定すると、
その関数を ClazzA.function() として呼び出すことができます。


すでに定義した Person クラスは、そのドメインに特化したビジネスロジックのみを持つものとしておきたい場合に、
データのシリアライズやデシリアライズのルールは分離しておきたい(Personの核となるドメインとは別にしておきたい)ことがあります。
このような場合に拡張関数を利用すると実現可能です。

import com.google.gson.Gson

// domain core module
class Person(val name: String, val age: Int) {
    // 空のコンパニオンオブジェクトを宣言しておく
    companion object {
    }
}

// client / server communication module
fun Person.Companion.fromJSON(jsonStr: String): Person {
    return Gson().fromJson(jsonStr, Person::class.java)
}

以下のように実行可能です。

val p1 = Person.fromJSON("""{"name": "Java Taro", "age": 45}""")
println("${p1.name} is ${p1.age} years old.")


まとめ

今回は、Kotlin のコンパニオンオブジェクトへの名前付け、インターフェースの実装、拡張関数の定義が可能であることを確認しました。



関連エントリ