秋の魔法使い

勉強したことのメモとか

自殺の文学史 感想

自殺の文学史という非常に面白い本を読みました。以下、簡単に内容と感想を書いてみます。

1章では、社会学、地理学、哲学、宗教、歴史 etcを軸にして自殺を論じており、自殺学の総合カタログの感があります。 カルト宗教の集団自殺や日本の切腹、心中など興味深いテーマにも言及しています。著者は日本文学を研究しているロシア人で、日本独自の文化に造詣が深く 世界的に見て自殺特異点である日本について特にページを割いてくれています。 各ページに散りばめられた古代から近代までの哲学者、宗教家、文学者たちの自殺についての見解や箴言は一つ一つ興味深く、力強いです。 ただし、生化学的な言及や臨床医学的な文献はあまり紹介されていません。あくまで思想上の知識に焦点が当てられています。

2章では、自殺により世を去った文学者たちの自殺理由について、恋愛、貧困、病気、飲酒 etc と分類して言及しています。 筆者が文学者に焦点を当てた理由は「傷つきやすく」「日記や作品に心情を細やかに記録している」からだとしており、文学者の自殺を通じて 自殺の一般的理由について光を当てようとしています。また、文学者独自の自殺理由については別に章立てて紹介してくれています。 日本人作家も多く紹介されており、特に馴染みの深い芥川、太宰、三島について、それぞれ相当の文量を割いて詳説しています。

最後に、古今東西の自殺した文学者のカタログが、簡単な生い立ちと自殺理由、その方法とともに紹介されています (全部で350人!)

全章を通じて多くの文学者、文芸作品が紹介されており、文学カタログとしても有用です。

話は少しズレますが、かなり昔に話題になった「完全自殺マニュアル」の序文に 「簡単に死ぬ方法さえ知っていれば人生気楽に生きられる」的なことが書いてあり、実際それはそのとおりかもしれない、と内容に期待したものですが、 実際に読んでみると、どの方法も (1番簡単確実と紹介されている縊死さえも) 非常に大変そうで、 死ぬのも中々楽ではないなあと逆に暗澹とした気持ちになった記憶があります。

自殺の方法よりも自殺の思想を知り、過去に旅立った文人たちの記録を読む方が気持ちが楽になることもあります。 しばしばこの世からの離脱を考えている自分のような人にこそ奨めたい本です。 自分はひどく落ち込んでいた時期にこの本を手に取り、生きることに対して少しだけ前向きになりました。

締めが思いつかなかったので、帯に書かれている筆者のまえがきを引用しておきます。

最近のある社会心理学者によれば、人類は自殺学的に五つのカテゴリーに分類される。

一、一度も自殺を考えない人

二、時に自殺を考える人

三、自殺をするぞと脅かす人

四、自殺を試みる人

五、自殺を成し遂げる人

第一のカテゴリーに属す幸せな人が、本書に興味を持つとは私には思えない。 本書は残りの五分の四の人類に捧げられたものである。

著者「まえがき」より

Kotlin sealed classを活用したい (願望)

sealed classはクラスの継承を制限するための機構です。 継承を同一ソースファイル内で定義したclassのみに制限します。(Kotlin 1.3)
残念ながら個人的にいまいち使いこなせていない (^^;) のでブログに使用法をまとめてみます。

拡張enumとしての利用

概念としては同じだが、propertyが微妙に異なるような場合に活用します。

// AmazonのようなECサイトを想定
// 自社倉庫管理商品とマーケットプレイス商品を定義する
// Item.kt
sealed class Item(
    val name: String,
    private val price: Int
) {
    abstract fun getPrice(): Int
}

data class PrivateItem(
    private val _name: String,
    private val _price: Int
) : Item(_name, _price) {
    override fun getPrice() = _price
}

data class MarketPlaceItem(
    private val _name: String,
    private val _price: Int,

    // 手数料がかかる場合がある
    val fee: Int
) : Item(_name, _price) {
    override fun getPrice() = _price + fee
}

// main.kt
val items = listOf(
    PrivateItem("自社商品", 1000),
    MarketPlaceItem("アディダス", 2000, 200)
)

val sum = items.sumBy { it.getPrice() }
println(sum) // -> 3200

// sealed classで定義すると同ソースコード以外での継承が不可能であることをコンパイラが認知できるためelse句が不要になる
val type = when (items[0]) {
    is PrivateItem -> "自社商品"
    is MarketPlaceItem -> "マーケットプレイス商品"
}
println(type) // -> 自社商品

Exception Handlingの代替

https://phauer.com/2019/sealed-classes-exceptions-kotlin/ など、 その他でもいろいろなところで紹介されているパターンです。
私は主に、domain層からinfra層のmethodをcallした際に、正常に終了した場合と、Domain的な例外 (処理自体は終了しているが、取得した値が不正だったりするケース) の表現に活用しています。

// SuccessとFailureを表現するsealed class
sealed class DomainResult<out S, out F> {
    class Success<S>(val result: S) : DomainResult<S, Nothing>()

    class Failure<F>(val result: F) : DomainResult<Nothing, F>()
}

// APIをcallしてKeyを取得するService class
object GetKeyService {
    private lateinit var api: GetKeyApi

    fun fetch(): DomainResult<SuccessResult, ErrorResult> {
        // 外部APIをcall
        val key: Key = api.get()

        // keyが正しい値の場合Successを返す。不正の場合はエラーメッセージを返す。
        // KeyNotFoundException() などはthrowしない
        return if (key.isValid())
            DomainResult.Success(SuccessResult(key))
        else
            DomainResult.Failure(ErrorResult("invalid key"))
    }
}

data class SuccessResult(
    val key: Key
)

data class ErrorResult(
    val message: String
)

data class Key(val value: String) {
    fun isValid() = value.isNotBlank() && value != "invalid"
}

// service call
// kotlin.resultを利用してみる
// https://github.com/Kotlin/KEEP/blob/master/proposals/stdlib/result.md
runCatching {
    GetKeyService.fetch()
}.onSuccess {
    when (it) {
        is DomainResult.Success -> {
            val key = it.result.key
        }
        is DomainResult.Failure -> {
            val errorMessage = it.result.message
        }
    }
}.onFailure {
    // IOExceptionなど. 明らかな例外をキャッチしてハンドリングする
    logger.info(it)
}

whenを使ったわかりやすい記述ができるようになり、例外をキャッチしてハンドリングする従来のやり方よりも可読性が向上します。

まとめ

実際に使っているところを見るとなるほどなーと思うのですが 自分で開発していて、ここはsealed classを使うべきだな、となかなか気づけないんですよね。自分の感覚に落とし込むにはもう少し実践が必要そうです。

IntelliJでExternal LibrariesのDebugをする

普通にbreak point設定できます。今までできることを知りませんでした ^^;
色々調査するときに便利です。stack trace追ったりとか。

f:id:radiochemical:20191031103046p:plain
IntelliJ-screen

ファーストクラスコレクションにコレクションのメソッドを委譲する

data class Book(
    val title: String,
    val price: Int
)

data class Books(
    private val books: List<Book>
) : List<Book> by books // コレクションメソッドをdelegate

// List<Book> -> Books
fun List<Book>.toValue() = Books(
    map {
        Book(it.title, it.price)
    }
)

fun main() {
    val books = listOf(Book("foo", 1000), Book("bar", 2000)).toValue()

    println(books.isEmpty()) // -> false
    println(books.size)      // -> 2
    println(books[0])        // -> Book(title=foo, price=1000)
}

自分でisEmpty() とか書かなくて良くなるので少し楽になります。
ただ、List実装に強く依存してしまい、公開したくないメソッドまで使えたりするので、その点は微妙かも。

HydraPak(ハイドラパック) ウォーターストレージ SEEKER インプレッション

HydraPak(ハイドラパック) ウォーターストレージ SEEKERを購入してみました。
この手のウォーターストレージのデファクトはプラティパスで、自分も愛用していますが

  • なんとなく強度が不安
  • 洗浄後乾くまでに時間がかかる

という点がちょっとだけ不満でした。特にワイン用のやつとか怖くて使えない。

で、この間PEAKSの記事でHydraPakを見かけ 値段もまあ手頃だしいっちょ買ってみっか、と試してみることにしました。 丈夫そうだし、口も広いし、何よりかっこいい。

試してみる

蕎麦粒山に持っていって、カップラーメン作ってみました。

くっさ!まっず!!!!!!

カップラーメンが驚くほどくさいよ。くさくてまずいよ。水を見てみたらちょっと黒く濁ってるし何より石油くさい。 くさすぎて喉が嚥下を拒否するレベル。とてもじゃないが使えない。勘弁してくれ。

洗い方が足りなかったのかも、と思い、帰宅後洗剤にしばらくつけ置きしてみたが効果なし。 amazon.comとかでは評価が高いから何か使い方間違えているのかもしれない。 それともやはりPEAKSの提灯記事など一切信じてはならないのだろうか?丈夫は丈夫なんですけどね。 MSRの似たような商品も水が臭くなると聞いたことがあるので、この手の商品は臭いについては妥協しないといけないのかもしれません。

とりあえず、まだまだプラティパスに頼ることになりそうです。 実際10年使ってて破れたことなんかないし、水も臭くならないですしね。

socket timeoutに関するちょっとした誤解

今まで握手してから完全にデータが到達するまでの時間、だと思っていたが、正確にはdata packet間のアイドルタイムの制限時間という意味だった。

https://www.baeldung.com/httpclient-timeout

the Socket Timeout (http.socket.timeout) – the time waiting for data – after establishing the connection; maximum time of inactivity between two data packets

https://stackoverflow.com/questions/7360520/connectiontimeout-versus-sockettimeout

A socket timeout is the timeout when waiting for individual packets. It's a common misconception that a socket timeout is the timeout to receive the full response. So if you have a socket timeout of 1 second, and a response comprised of 3 IP packets, where each response packet takes 0.9 seconds to arrive, for a total response time of 2.7 seconds, then there will be no timeout.

なるほどなー

I wish they had named "socket timeout" as "idle timeout".

禿同