yak shaving life

遠回りこそが最短の道

2021年振り返り的な何か

いやね、分かってますよ。もう一月も終わろうとしているわけで。こういうのって普通2021年末にやるか、遅くとも年始くらいにやるでしょ。1/31て。まあ自分の中で「一月中ならギリセーフ」みたいな謎の一線があるのでそこのギリギリのラインを攻めて行きたいと思います。(?)

というわけで昨年の年始…もとい、二月に設定したOKRを振り返ってみようと思う。しかしOKRを真面目にやったことがないので振り返る方法もよく分からない。ちゃんと調べるのも面倒なので雰囲気でやってみよう…とりあえず各Key Resultを見ていった上で、当初の目標になかった成果等も加味して最終的な評価(0~1?)つける。これで。

二月の記事で設定したObjectiveは「初心に返って学び直しをする」だった。各Key Resultについて一つずつ見ていく。

Key Results

技術書を25冊読む

ブログ記事の「技術書」カテゴリを見ると、9冊しかない。あれれ~おかしいぞ~?(名探偵)

実際にはSoftware DesignとかWEB+DB PRESS読んだり、他にもサーバレスアーキテクチャの本とかJavaRuby関連書籍、マネジメント系の本etcをいくつか読んではいるのだが、如何せん最後まで読み切らないケースが多くて記事を書く気にならないのであった。(最後までちゃんと通読して、理解したことをまとめないと記事を書く気にならない…)

実際には25冊近く読んでいる気はするのだけれども、最近記憶力があからさまに落ちてきていて、しっかり記事にするくらいしないとなかなか記憶に定着しないので、ちゃんと25記事書く形にしたかった。達成率低すぎィ!

今年は25記事をガチで目指そう…

ソフトウェア開発以外の本を10冊読む

記事としては8記事となってまたまた未達成。これもまた実際には図書館で借りてきた仏像・観光・建築・アート・お金あたりの本をまあまあ読んでいて、こちらは完読したものも多い。でも途中から面倒になってきて記事にしていないのであった。

「直島誕生」とかはすごく面白かったので読書感想文を書きたかったのだけれども、どうも仕事が忙しくてそもそもブログを書く気力がなかった…。今からでも書きたいけどだいぶ忘れてしまったなあ。

新しいコミュニティに2つ以上参加して継続する

目標を立てた時点でイメージしていたのは、(自分にとって)新しい技術コミュニティに参加していくことと、オンラインサロンというものに一度入ってみようかなという感じであった。エンジニアと人生コミュニティとか。(元々はサロンという名前だった気がする)

が、実際はだいぶ方向性が変わっていて、まずこの情勢であまり勉強会やカンファレンスなどに参加する気になれなかった。そもそも育児になるべくリソースを割きたいので業務時間外の時間の使い方がかなりシビアであり、JJUGセミナー何回か聞いたりrust-jp Slackに入った程度で終わってしまった。

また、縁あってフィヨルドブートキャンプというプログラミングスクールにメンターとして参画することになった。正直プログラミングスクール業界については完全に訝しんでいたのだが、フィヨルドブートキャンプ通称FBCは自分の知っているスクールとはだいぶ違った。そもそもいい評判を聞いていたし、知り合いが中にいたので色々話を聞いて、是非お手伝いしたいということでメンターの末席を汚させてもらっている。メンター陣が豪華すぎて自分なんかが居てもいいものかと思ったりもするが、まあ自分なりに頑張ってプログラミングを学びたい人をサポートしている。

で、なぜこの項目でFBCについて触れたのかというところ。FBCはスクールという感じがあまりしなくて、むしろ「コミュニティ」感が強い。受講生とメンターという立場の違いはあれど、個人的にはプログラマとして一緒に頑張る仲間のように(勝手に)感じている。例え未経験であれ、プログラミングを頑張っている時点でもうプログラマなのだ。もちろんメンターとしての責務はしっかり果たすよう努力しているが、それにしてもDiscordで技術に関係あることやないことをワイワイ話しているこの感じは「コミュニティ」以外の何物でもないと思う。

そんなわけで、今の自分にとってFBCは副業先でもあり大切なコミュニティでもある。「2つ以上参加」は達成できなかったが、継続して参加できるコミュニティが一つ見つかっただけでも個人的には十分な成果だった。引き続きメンター業頑張ります。あ、プログラミングを学びたい方はフィヨルドブートキャンプがおすすめですよ〜是非見てみてください!(唐突な宣伝)

bootcamp.fjord.jp

仕事で使用している技術スタック全てを基礎から勉強し、同じスタックで個人プロダクトを出す

はい。やってません。ごめんなさい。

誰に謝っとるんだという感じではあるが、弁明します(誰に?)。代わりといってはなんですが、仕事で一から小さなアプリケーションを一人で作りました。半ば無理やり自分でやった。やりたかったから。今では反省している。

まあこれが結構いい経験だったので、頑張ってやってよかったと思う。一から作るところの経験をするのが目的だったので実質達成と言っていいのでは…!?いやダメか。今年はやろう…(毎年言ってる)

あと、「公式ドキュメント全部読む」をやらないといけない。これを強く感じた。Springのドキュメント、多いなあ…。 公式ドキュメント全部読むに関して、何度も読み返したいQuora回答はこちら。この文章は本当に素晴らしすぎる。

qr.ae

英語の勉強をして何かしらの試験を受けてスコアアップ(TOEIC換算で比較)

ELSAをやったり、Rust the bookPoEAAを英語で読んだり(両方未完)したものの、どうにも中途半端になってしまった感が拭えない。

最近はJolly Phonicsというのを子供と一緒にやっていて、発音を少しでもマシにしたいなー等と思っている。しかし子供はこれを勉強などとは露ほども思わずただただ楽しい遊びだと思ってやっているので、上達がめちゃめちゃ早い。耳がいいとかカタカナ英語を知らないというのもあるだろう。とにかくやたら発音が良くてどう考えてもお父さんは完全なるジャパニーズイングリッシュ。娘に「違うよーこうやっていうんだよ。お口の形をよく見て」とか言われて日々教えられてます。お父さん頑張ります。。

試験で言うとスピーキングの試験を受けた。正直微妙だった。TOEIC換算を直接的にすることはできないが、Cambridgeのレベルで言えば、全然上達はしてなかった。現状維持くらい。うーむ、英語ムズカシイ。継続的にやるしかないな。

ブログをなんでもいいから100記事書く

50記事だった。ちょうど半分。特に後半の失速具合がすごい。毎日書いてる人とか化け物では?

娘が遊ぶためのWebアプリの新作を出す

イデアに実装力と気力が追いついてなくてできなかった。ただただ無力。もうちょっとしたらPCとか触れそうだしタイピングアプリとか作るのがいいかもなーとぼんやり考えてはいるが、何年か先かな…

プロダクト概要だけ書いて全く開発の進んでいない個人開発モノを全てインターネット上に公開するところまでやる

逆にプロダクト概要だけのものが増えた。

Twitterは一日一時間(?)

平均したら達成している可能性はあるけどそもそも測定するの忘れてた。スマホ変えたし。

技術系の資格を何か取ってみる

AWSのなんかソリューションなんとかアーキテクトみたいなやつを受けよう受けようと思ってたら一年終わってた。

その他

技術以外のところで新しいことをたくさん学んだ気がする。仏像から始まって建築、アート、観光、お金、日本史、アパレル、不動産あたり。学校の成績とかは良かったし十代の頃は自分のことを博識だと思っていた(恥ずかしい!)のだが、今や知らないことが多すぎて逆に楽しくなってきた。全く素人な分野はちょっとかじっただけでどんどん知識が増えて良い。読書が一番優良なコンテンツだと思うけど、最近はYouTubeにも色々あって良い。ただ質の良し悪しを見分けづらいのが難点。あと大河ドラマは良い。

浅く広く知りたいタイプなので、様々な方面に手を伸ばしていきたい。

総評

総じてKRがズタズタ。なーんにも達成してない。でも気持ち的には「去年結構色々やったし学び多かったんでは?良くない?」てな感じなので、まあいっか。数字つけるとしたら0.2 ~ 0.3くらいな気がするけど。低。

「初心に返って学び直しをする」はどのくらいできたのか定性的に考えてみると、技術面ではどうかちょっと分からないけどそれ以外の領域では初心に帰るというより初心者丸出しで色々勉強できたので結果的には割とできたんではないかな。うんうん。自分を褒めるスタイルでいこう。

OKRのおかげでチャレンジすることの方向性をある程度ぶらさずにいられたような気がしなくもないので、今年もやったほうがいいかな。でも達成できてなさすぎて微妙に凹んでもいるので、悩むなあ。うーむ。

あ、書いてるうちに二月になってしまった…(また一つ目標達成できなかった感)

まあ人生全体的にこんな感じな気がするな。のらりくらりとやっていこう。

Pixel 6 をしばらく使ってみた感想

Pixel 6を買って二週間ほど経ったので、レビュー記事というほどではないですが感想をつらつら書きたいと思います。まぁまぁ長いので、忙しい方はtl;drだけ見てください。

tl;dr

総合的に見て良い端末だと思います。画面デカいけど。価格も高すぎないし特に不満点なし。画面がデカくてもいい人にはオススメです。

感想

筐体について

でかい。とにかくでかい。6.4インチって片手で操作するの厳しくないですか?iPhoneも巨大化してきているし、世の人々はどうしているんだろう…不思議だ。

以前使っていたPixel 3は5.5インチで、手に馴染むいい形だったので片手で自由に操作できていたのだが、Pixel 6は無理。絶対無理。上の方とか親指届くわけない。まあでも自分より手が小さい人は5インチでもそれは無理だったりするわけで、すべての人が片手で扱えるスマホというのは存在しないか。であれば大きくした方が色々詰め込めるし電池も大きくなるし動画も見やすいというのでスマホがどんどん巨大化するのは必然なのかもしれない。とはいえ5.5インチが恋しい…。

もちろんいい点はあって、Pixel 3と比べると動画はやはり見やすいし、電子書籍も若干読みやすい。固定レイアウトでなければ技術書読むのもスマホでいいかなと思えるようになったのでこれはかなりプラスかもしれない。

また、カメラバーという独特なデザインについて。これは正直結構いいと思う。見た目的にもすぐ慣れたし、カメラの部分だけ出っ張っていると(iPhone 13のカメラを見よ)置いたときに不安定になったりするが、バーだと安定。ド安定。しかもバーの分ちょっと浮くので掴みやすい。ほら、ツルッツルの机にスマホ置いたら滑ってなかなか取れないみたいなことありません?ない?あそう。まあ僕はあるんですよ。ごく稀にですけど。カメラバーがあるとそういうトラブルとは無縁。地味に良い副作用(?)だと思う。あとバイブでブルブル滑って動いちゃうみたいなこともないです。

指紋認証について

背面の指紋認証ではなく、ディスプレイ内指紋認証になりました。精度はどうだろう、よくはない気がする。ちょいちょい失敗する。が、背面のときも結構失敗してたし体感的には同じくらい。iPhoneと比べるとどうなのかはわからないけど、マスク有りの顔認証に比べたら断然いいでしょう。 家の中で指紋登録して、外で認証しようとすると指先が乾燥しているからか全然通らなかったので、外で指紋登録し直したら結構イケるようになった。ちょっとワークアラウンド感強いですけど同じ悩みのある方にはオススメです。

個人的には置いた状態でアンロックできる分背面より良い。

カメラについて

画質は良い。Proはもっといいらしいけど個人的には十分。ズームは7倍までできて結構使い勝手が良い。

写真については完全にド素人だしあまり良くわからないけど、Pixel 3に引き続きポートレートモードにするといい感じのボケ写真が撮れます。ピンぼけ処理はソフトウェアでやってるらしくたまに不自然になるが、大抵いい感じになってくれる。のでいいんではないでしょうか。

あとは暗いところでの写真がかなりキレイに撮れる気がする。同じ場所でiPhone 10(古くて申し訳ない)と比べると圧倒的に見やすい写真が撮れる。夜景モードにするとさらに鮮やかに。これは結構いいところです。

あとはQRコードの認識が早くなった気がする。というかPixel 3が遅すぎただけか…。遅いというか場合によってはLensを起動しないと読み込んでくれなかったからなあ。ここのストレスがだいぶ軽減されました。

あとは消しゴムマジックなるものが搭載されていて、写真を撮ったあとで周辺に写り込んだ人なんかを消すことができる。機械学習的なアレで消した部分の画像を生成していてTensor SoCの本領発揮というところなのかもしれないけど、個人的にはうーんという感じ。割と不自然になる。消したい対象が相当小さい場合にはそこそこ良い感じになるのでいいかもしれない。

普段の使い心地について

今のところスペック不足を感じたことはなくて、サクサク動くし電池も持つし満足度は高め。買ったばかりなので電池持ちがいいのは当たり前かもしれないけど、外出してそれなりにブラウジング、カメラ(動画)、ゲーム等を使っても一日余裕で持ちます。4614 mAhは伊達じゃないという感じ。僕は動画はあまり見ないのでYou Tubeを延々見るとかするとどうなるかはちょっと分からないけど、筐体をデカくした分電池持ちは良くなっているんじゃないでしょうか。

前述の通りだいぶ画面サイズが大きくなったので、割と両手で扱うようになりました。まあこれは慣れの問題なのでいいんだけど、まれに片手が塞がってるけど空いてる方の手でスマホを触りたいときがあって、そういうときは若干困る。どうしたものか…。まあでもほぼ全メーカーのスマホが巨大化傾向にあるので、BALMUDA Phoneを買うくらいしか回避策はなさそう。

それから、ジェスチャーナビゲーションと3ボタンナビゲーションという切り替えが可能になりました。 3ボタンナビゲーションは従来の「ホーム」「戻る」「アプリの切り替え」のソフトウェアボタンが画面下部に表示されるもの。それに対してジェスチャーナビゲーションは「画面下部から上にスワイプでホームに移動」「左端または右端からスワイプで戻る」「下から上にスワイプから長押しでアプリの切り替え」というiPhoneっぽい操作が可能になります。

これが結構良くて、3ボタンだと戻るボタンが遠い(くどいようですが画面がデカいので…)ため親指が大変なところ、ジェスチャーなら右端から左にスワイプなのでかなーり楽になる。ホームも慣れれば快適、「アプリの切り替え」は慣れるのにちょっと時間かかるけど慣れればそれなり。といった感じです。

面白いのは、iOSと違って「進む」がないこと。左からスワイプしても右からスワイプしても「戻る」になる。これはiPhoneユーザからすると相当戸惑うんじゃないかと推察しますが、個人的には好き。進むってあんまり使わないし、右利き左利きどちらでも同じような体験ができるのは良いことだと思う。この右からスワイプで戻る機能がなかったら3ボタンナビゲーションにしていたかもしれない。

難点としては普通の横スワイプが戻るになってしまい、ジャンプ+を閲覧中に何度も何度一覧画面に戻ってしまい、WRYYYYYYYY!と頭を掻きむしりそうになってしまうことでしょうか。まあこれは設定で「戻る」の感度を「低」にすることでマシになりました。やれやれだぜ…。

その他使っていない機能など

文字起こしとかリアルタイム翻訳の機能が良いらしい。これもTensor SoCのなせるわざでしょうか。でも使ってないしこれからもあまり使う機会がなさそうなので、このあたりについて知りたい方はYou Tubeとかでレビュー動画を見るのが良いと思います。

Pixel Standは持っていないのでどうか分からないですが、リモートワークで仕事部屋をしっかり整えている人なんかは良さそう。普通にサードパーティのQi充電器でもワイヤレス充電できそうなのでそれでも十分かもです(試してない)。

あとは、ネットニュースで様々な致命的バグが報告されているというのを見かけます。勝手に電話がかかるとか、充電できないとかなんとかかんとか。幸運なことに自分はどれにも当たっていないし、今のところ全てのバグはソフトウェアアップデートで解消されているあるいは解消される見込みらしいのでそんなに気にしなくても良さそうです。

まとめ

ダラダラと書きましたが、基本的には満足しています。正直画面サイズは5.5インチくらいがいいんだけど、スマホの巨大化は抗えない流れだと割り切っています。まあ本とか読みやすいし電池持ちも良くなって悪いことばかりではないですし。

お値段もそこまで高くない(Pixel 3はなんやったんや…)ので、Androidユーザにはオススメできる端末だと思います。

Proの方はよく知らないんですけどカメラと画面サイズくらいしか違いはなさそうだし、より大きい方が好きな人はProを選べばいいんじゃないでしょうか。知らんけど。

今更ですが、色はSorta Seaformにしました。なかなかキレイな色なのでオススメです。ああ、あとストレージはなるべく256GBにしたほうがいいと思います。長く使いたいなら特に、128GBだとそのうち足りなくなること必至です。それでは。

Pixel 6 を買った

買いました。

Pixel 3をおよそ3年前に買って以来ずっと使っていて、正直デバイスとしての不満は全然ありませんでした。今でもサクサク動くし、指紋認証使いやすいし、カメラは綺麗だし。カメラを起動するとメモリを使い果たして全てのアプリがキルされちゃうけどそこはご愛嬌。

ただ、充電が持たなくなってきたのと、電源ボタンが時々埋もれてしまい半分押しっぱなし状態(勝手に電源が切れたり、カメラ起動したりとめちゃくちゃな挙動をする)になってしまうことがあり、また充電ケーブルを挿しただけでは充電できない問題(サポートに問い合わせたけど解決せず)もあるのでそろそろ買い替えどきかなとは思っていた。

Pixel 4はなんか微妙だなと思い、4aも同様、5は良さそうだけどちょっとスペック低いな…?5aは言わずもがな…てな感じで様子見に様子見を重ね、6が来てやっと、これや!と思ったわけです。思ったんですが、Tensor SoCが果たしてどの程度の出来なのか、初おろしの製品だし重大なバグがないだろうか、それにお値段もそこそこするしハードウェアスペック的には正直そこまででもない…本当に買いなのか?ぶっちゃけPixel 3のままでいいのでは…?

等々の葛藤の末、Google様へのお布施だと思い、えいやで購入ボタンを押している私がいました。Big Techに世界を便利にしてもらうためにどんどんお布施していかないとね。つーわけで来たんですよ。やっと。悩んでいるうちにみんなどんどん注文していたっぽくて、Google Storeを見るたび配送予定日が遅くなっていたんですね。実際は表示されていた予定日よりだいぶ早く来たのでよかったです。

というわけで早速開けたかったけれども、子供が寝てからにしようと思っていたら子供を寝かしつけながら一緒に寝てしまうという失態を犯し、一日越しでついに開封しました。テンション上がってきた。

電源をつけて、指示に従いセットアップ。今時のAndroidは端末同士をケーブルで繋いで移行できるので便利。昔はどうやってたかなー。なんかよくわからんけど自力でアプリとか落としてきて全部手動でセットアップした気がする。思い出しただけで辛い。そのままサクサク進めて、数十分ほど待って完了。楽チンですなあ。

ちょっと触ってみた感想。でかい。ギリ許容できるレベルの大きさかな。個人的にはPixel 3くらいの画面サイズがちょうどいいんだけどなあ。デカすぎて右手で持ったとき左端まで親指が届かない…。iPhoneみたいに左端からスワイプして「戻る」ができるんだけど、ちょっと実用性がないのでは…と思ったら、右からスワイプでもいいらしい。ほう。こりゃ便利じゃあないか!というわけで従来の3ボタンナビゲーション(画面下部に「戻る」「ホーム」「アプリの切り替え」の3ボタンがある)ではなくてiPhone風のジェスチャーナビゲーションでいくことにしました。良さそう。

画面のヌルヌル感はiOSと遜色ない感じ。画面上の指紋センサはちょっと時間かかるけど今のところ精度は問題なさそう。保護フィルム貼ったときどうなるかが気になる。カメラはまだちゃんと使ってないけど画質いい感じ。Pixel 3にあった、本体横両側をぎゅっと握りしめるとGoogle Asistantが起動するやつはないのかー。地味に使ってたのになあ。まあ他に使ってる人いなさそうだけども。

そんな感じで、パッと見とても良さそうだなという印象。消しゴムマジックとか自動翻訳とかTensor SoCが本領発揮しそうな機能はまだ使ってないけど。発熱がきついという噂もあるし充電がどの程度持つかとかも気になるので、ちゃんとした使用感はまた後日書こうと思います。他にも買った人いると思うんで、是非感想書いてください。読みたいです。

Spring Data RedisでZPOPMIN(MAX)を使う

RedisにはSorted Setというデータ型があって、ユーザランキングみたいなものを作るときに便利だったりする。このSorted Setに対する操作はZADDとかZRANKのようにZから始まるものとなっている。

Sorted Setから一番スコアが低い(高い)ものを破壊的に取り出すZPOPMIN(ZPOPMAX)というコマンドがあり、Spring Data Redisでこれらを使いたかったのだがやり方がわからず、調べてもなかなか出てこないので苦労した。ので、解決までの道のりをメモ。やり方だけ知りたい人は最後の方のサンプルコードを見てください。検証に使っているSpring Data Redisのバージョンは2.5.6で、Javaは11。Redis ConnectorはLettuce。

まず、サポートされているコマンドは以下のように利用できる。

ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
zSetOperations.add("ranking", "user1", 100);
zSetOperations.add("ranking", "user2", 200);
Set elements = zSetOperations.range("ranking", 0L, 1L);

System.out.println(elements);
// 出力 => [user1, user2]

zSetOperations.addZADDzSetOperations.rangeZRANGEコマンドを実行してます。簡単ですね。

ところがZSetOperationsクラスにはpopMinとかpopMaxみたいなメソッドがありません。こいつは困った。色々調べたけどよくわからない。そうこうしているうちに以下のissueに辿り着いた。

github.com

要は次くらいのバージョンで対応してZPOPMIN, BZPOPMIN, ZPOPMAX, BZPOPMAX, ZMSCOREが使えるようになるとのこと。へー。でも僕は!今やりたいんです!どうすりゃいいの!と思っていたら興味深いコメントが。

When using Lettuce, you need to provide a CommandOutput to capture the Redis response. For [B]ZPOP[MIN|MAX] that's new ScoredValueOutput<>(ByteArrayCodec.INSTANCE) (via execute(String command, @Nullable CommandOutput commandOutputTypeHint, byte[]... args)).

Spring Data Redis doesn't have yet command output hints for these commands.

なるほど、要はRedisTemplateではできないからLettuceのexecuteコマンドでやれってことね。ふむふむ。というわけでリファレンスを見る。

docs.spring.io

なるほどわからん…。数時間溶かしてなんとかできたのが以下。各行に何やってるかコメント書いてます。

 // ここはさっきとほぼ同じコード
ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
zSetOperations.add("ranking", "user1", 100);
zSetOperations.add("ranking", "user2", 200);
Set elementsBefore = zSetOperations.range("ranking", 0L, 1L);
System.out.println("Ranking before ZPOPMIN : " + elementsBefore);
// => Ranking before ZPOPMIN : [user1, user2]

// LettuceConnectionを取得。キャストするのがミソ。キャストせずRedisConnectionのままだとexecuteが通らない
LettuceConnection conn = (LettuceConnection) redisTemplate.getRequiredConnectionFactory().getConnection();

// 実行。第2引数がミソ。戻り値はObject型
Object resultObject = conn.execute("ZPOPMIN", new ScoredValueOutput<>(ByteArrayCodec.INSTANCE), "ranking".getBytes());

// executeの戻り値はScoredValue型にキャストできる。ここの型を変えれば他のコマンドにも対応できそう
ScoredValue scoredValue = (ScoredValue) resultObject;

// getValueでvalueが取れるが、戻り値はObject型
Object valueObject = scoredValue.getValue();

// Stringを入れてるならStringに変換できる。直接はキャストできないのでbyte配列にしてから
String value = new String((byte[]) valueObject);
        
// scoreはdoubleで入ってるのでキャストとかは不要
double score = scoredValue.getScore();
        
// valueとscoreが取れてめでたしめでたし
System.out.println("Popped element : value = " + value + ", score = " + score);
// => Popped element : value = user1, score = 100.0

// POPしたのでSorted Setの中身が一つ減っていることを確認
Set elementsAfter = zSetOperations.range("ranking", 0L, 1L);
System.out.println("Ranking after ZPOPMIN : " + elementsAfter);
// => Ranking after ZPOPMIN : [user2]

conn.close();

このサンプルコードがググってさっと見つかればこんなに苦労することもなかったのになあ。。 ということで一応デモアプリをGithubにあげておいた。誰かの役に立てばいいけど。

github.com

追記:connectionをcloseしてなかったのでconn.close()を追加。

東京都現代美術館で GENKYO 横尾忠則 などを観た

この前 The Artists にも行ったのだが、GENKYO はもう規模が桁違いだった。とにかく横尾忠則作品がものすごい数展示されていた。活動期間がとても長い方なので、年代ごとに作風が全然違う。それがうまくカテゴリ分けされていて素晴らしい展示だった。

横尾忠則作品といえば、若い頃のアングラっぽい派手な色と女性が特徴的なポスターだったり、書き込み量が異常に多くて宗教や西洋美術のモチーフが大量に詰め込まれたような難解かつ複雑な絵画なんかは観たことがあったけれども、それ以外にもY字路シリーズとか「タマ、帰っておいで」とかまあ色んな作品があった。量だけはかなりたくさん観た気がするので、少しずつ横尾作品が分かるようになっていきたい。

その後はマーク・マンダースの特別展示を見たり、コレクション展を見たり。マーク・マンダースは初めてじっくり観たけど、どういうコンセプトなのか不思議だ。立体は表現方法が色々ありすぎてカオスで面白い。本人のインタビューとか解説をもうちょっと見たいなあ。コレクション展の方でも色々あって面白かったけど、平田実の写真展示でハイレッドセンターの「首都圏清掃整理促進運動」があり、あっ、本田パピヨン先生の漫画*1で見たやつだ!という進研ゼミ的体験をしたりして楽しかった。

1日でかなり多くの作品が観れて良かった。都現美いいとこみんなで行こう。

iPadは教科書代わりになるのか

息子が学校の教科書をPDF化してiPadだけ持って登下校しているという話を見た。

togetter.com

本当か嘘かみたいなところはどうでもよくて、はてブコメントが面白い。特に否定派のコメントはある意味参考になる。人は変化を嫌う生き物なんだなーというのがよくわかるというか。リツコさん風に言うとホメオスタシスというやつだろうか。全自動洗濯機が発売された当初、「洗濯は愛情を込めて手でするもの、機械がやるなんてあり得ない」と言われなかなか受け入れられなかったという話を聞いたことがあるが、どの時代も同じという感じがするなあ。

iPadがあれば(紙の)教科書はいらないのかというとどうだろう。個人的な経験からすると紙の方が便利そうに感じるけれども、初めからiPadしかなければその環境で十分に育っていくのが人間だという気もする。教育は結果が出るのに時間がかかるし効果測定が難しそうなのでなんとも言い難い。まあでもクソ重い教科書の持ち運びは意味ないからやめた方がいいでしょうね。

それはさておき、少し前に買ったキングジムのフリーノのことを思い出した。自分ではあまり使っていないのだが、奥さんが試験勉強にガッツリ活用していて面白いなと思った。PDFの問題集を端末に入れて、そこに書き込んでいくという感じ。いくらでもコピーできるし書き直しもできるし検索もできるというので紙より便利そう。いつでも持ち運べるし。もしかしたら、教育用にはiPadみたいな汎用タブレットより電子ペーパーのデジタルノート端末の方が向いているかもしれない。あーでも動画とか見れないのはちょっときついか…iPadで動画や資料を見て、フリーノでノートを取る。みたいな感じが一番いいのかもしれないけど、そこまでリッチな環境を全学生に提供するにはまだまだかかりそうだ。教育のIT化も難しそうだ。いつか携わってみたいところではあるけどまあ茨の道だろうな…。

HomebrewでJmeterをインストールしたらちゃんと動かなかった

諸事情によりJmeterGUIを動かしたかったのでMacでのインストール方法を調べると、Homebrewにあるとのことだったのでインストールした。が、ちゃんと動かなかったのでやったことをメモ。

環境

macOS 10.15.13(Catalina), JavaはOpenJDK 11.0.4, MacBook Pro Early 2015。M1 Macの新しいやつほしい。

事象

brew install jmeterJmeterをインストールして、jmeterコマンドでGUIを実行。WARNING: package sun.awt.X11 not in java.desktopとかいうのが出てるからなんとなく嫌な予感がしたが、一部の機能が動かない。具体的には File -> Open を押しても何も起こらない。(何もできねえ…)

ターミナルを見るとこんなエラーが出力されている。

Uncaught Exception java.lang.IllegalAccessError: class com.github.weisj.darklaf.ui.filechooser.DarkFilePaneUIBridge$DetailsTableModel (in unnamed module @0x4c40b76e) cannot access class sun.awt.shell.ShellFolder (in module java.desktop) because module java.desktop does not export sun.awt.shell to unnamed module @0x4c40b76e in thread Thread[AWT-EventQueue-0,6,main]. See log file for details.

なるほどわからん。ログファイルを見ろと言われているので、カレントディレクトリに生成されているjmeter.logを見る。

2021-10-26 01:27:40,693 ERROR o.a.j.JMeter: Uncaught exception in thread Thread[AWT-EventQueue-0,6,main]
java.lang.NoClassDefFoundError: Could not initialize class org.apache.jmeter.gui.util.FileDialoger
        at org.apache.jmeter.gui.action.Load.doActionAfterCheck(Load.java:75) ~[ApacheJMeter_core.jar:5.4.1]
        at org.apache.jmeter.gui.action.AbstractActionWithNoRunningTest.doAction(AbstractActionWithNoRunningTest.java:44) ~[ApacheJMeter_core.jar:5.4.1]
        at org.apache.jmeter.gui.action.ActionRouter.performAction(ActionRouter.java:87) ~[ApacheJMeter_core.jar:5.4.1]
        at org.apache.jmeter.gui.action.ActionRouter.lambda$actionPerformed$0(ActionRouter.java:69) ~[ApacheJMeter_core.jar:5.4.1]
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318) ~[?:?]
        at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771) ~[?:?]
        at java.awt.EventQueue$4.run(EventQueue.java:722) ~[?:?]
        at java.awt.EventQueue$4.run(EventQueue.java:716) ~[?:?]
        at java.security.AccessController.doPrivileged(AccessController.java:399) ~[?:?]
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86) ~[?:?]
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:741) ~[?:?]
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) [?:?]
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) [?:?]
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) [?:?]
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) [?:?]
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) [?:?]
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:90) [?:?]
2021-10-26 01:27:40,842 ERROR o.a.j.JMeter: Uncaught exception in thread Thread[AWT-EventQueue-0,6,main]
java.lang.NoClassDefFoundError: Could not initialize class org.apache.jmeter.gui.util.FileDialoger
        at org.apache.jmeter.gui.action.Load.doActionAfterCheck(Load.java:75) ~[ApacheJMeter_core.jar:5.4.1]
        at org.apache.jmeter.gui.action.AbstractActionWithNoRunningTest.doAction(AbstractActionWithNoRunningTest.java:44) ~[
ApacheJMeter_core.jar:5.4.1]
        at org.apache.jmeter.gui.action.ActionRouter.performAction(ActionRouter.java:87) ~[ApacheJMeter_core.jar:5.4.1]
        at org.apache.jmeter.gui.action.ActionRouter.lambda$actionPerformed$0(ActionRouter.java:69) ~[ApacheJMeter_core.jar:5.4.1]
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318) ~[?:?]
        at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771) ~[?:?]
        at java.awt.EventQueue$4.run(EventQueue.java:722) ~[?:?]
        at java.awt.EventQueue$4.run(EventQueue.java:716) ~[?:?]
        at java.security.AccessController.doPrivileged(AccessController.java:399) ~[?:?]
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86) ~[?:?]
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:741) ~[?:?]
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) [?:?]
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) [?:?]
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) [?:?]
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) [?:?]
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) [?:?]
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:90) [?:?]

なるほどわからん(2分ぶり2回目)。とりあえずorg.apache.jmeter.gui.util.FileDialogerがクラスパスにないんだろうけどどうすればいいやら。

解決策

エラーメッセージ等でしばらくググって色々試したけどどうも解決できず。Javaのバージョン下げろとか上げろとか色々書いてあったので、jenvを入れて8とか17とかも試してみたけど変わらず。

こいつはちょっとヤクすぎる(yak shavingすぎる)なと感じ始めたので、別のアプローチを試すことに。[Jmeter公式]に行くとバイナリをダウンロードできるので、これをダウンロードしてみることに。その間にhomebrew版は消しておく。

大体以下のようなコマンドを打った。

$ brew uninstall jmeter
Uninstalling /usr/local/Cellar/jmeter/5.4.1... (2,645 files, 124.4MB)

# 一応Checksumを計算してみる。ちゃんと合ってるっぽい。
$ shasum -a 512 apache-jmeter-5.4.1.tgz
bfc0faa84769b58c1fd498417b3a5c65749f52226bd6e3533f08ca7ea4a3798bb8d2cbd7091b443dd6837f3cbea5565c3c18e6497b40bec95616bf44dfdf590d  apache-jmeter-5.4.1.tgz

$ tar xzvf apache-jmeter-5.4.1.tgz
(出力略)

$ cd apache-jmeter-5.4.1/bin/

$ sh jmeter.sh
================================================================================
Don't use GUI mode for load testing !, only for Test creation and Test debugging.
For load testing, use CLI Mode (was NON GUI):
   jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder]
& increase Java Heap to meet your test requirements:
   Modify current env variable HEAP="-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m" in the jmeter batch file
Check : https://jmeter.apache.org/usermanual/best-practices.html
================================================================================

お、Homebrew版で出ていたWARNINGが出てない!これは期待!

ということで、実際に立ち上がったGUIではFile -> Openも動きました。エラー出力もなし。めでたしめでたし。

Homebrew版のエラーを解消する方法は結局分からなかったけど、まあ動いたからよしとしよう。今日もyakをshavingしたので人生を生きているなあ。