心配ゴム用 (^ω^)ニニニニニつ ビヨーン

gyazo.com

const buildBiyon = (max) => {
  let incr = 1;
  let count = 0;
  return () => {
    if (count === 1) {
      incr = 1;
    }
    if (count >= max) {
      incr = -1;
    }
    count = count + incr;
    return "ニ".repeat(count);
  };
};

(() => {
  const biyon = buildBiyon(5);
  setInterval(() => {
    history.replaceState({}, '', location.pathname+location.search+`#心配ゴム用 (^ω^)${biyon()}つ`)
  }, 100);
})()

See also blog.sushi.money

Kiritoru: 見ているページをScrapboxでブクマをAndroidの共有メニューから簡単にできるように

scrapit.vercel.app

……というのを作った。

ソースコード: GitHub - aereal/scrapit

blog.sushi.money

PCのブラウザではこういうブックマークレットでブクマしている一方、Androidで見ている時にぱっとやる方法がなくて、ブラウザのブックマークに入れておき後でPCを開いて丁寧に移すということをしていたけれど面倒だった。

きっかけは忘れたけれどWeb Share Target APIという存在を知って、Webアプリでできるならと思って試してそつなく動いている。半日で完成したので満足。

Web Share Target APIはmanifest.jsonに共有されたら開かれるURLを書いておくと、Androidの共有メニューで選択されたらそのURLが開かれるのでその先はアプリで好きにできる、という仕様。
現時点でのステータスはunofficial draftなのでそういうつもりで接します。

Next.jsでPWA

NetlifyもFirebase Hostingも使ったことあるしVercelは触ったことないので試してみよう、Next.jsと良く統合されているっぽいのでcreate-react-appでも良いけどNext.jsにすることにした。

next-pwaを使うとWorkboxを使って良い感じにService Workerに登録するスクリプトをホストしてくれる。

イニシャルで特定される都道府県

anond.hatelabo.jp

ルール:

使ったコードは以下:

#!/usr/bin/env ruby

require 'abbrev'

prefs = DATA.each_line.map {|l| l.strip.split('-').first.downcase }
abbreviates = Abbrev.abbrev(prefs)
unique_prefs = abbreviates.keys.select {|k| k.size == 1 }.map {|k| abbreviates[k] }
puts unique_prefs

__END__
Hokkai-do
Aomori-ken
Iwate-ken
Miyagi-ken
Yamagata-ken
Fukushima-ken
Ibaraki-ken
Tochigi-ken
Gunma-ken
Saitama-ken
Chiba-ken
Tokyo-to
Kanagawa-ken
Niigata-ken
Toyama-ken
Ishikawa-ken
Fukui-ken
Yamanashi-ken
Nagano-ken
Gifu-ken
Shizuoka-ken
Aichi-ken
Mie-ken
Shiga-ken
Kyoto-fu
Osaka-fu
Hyogo-ken
Nara-ken
Wakayama-ken
Tottori-ken
Shimane-ken
Okayama-ken
Hiroshima-ken
Yamaguchi-ken
Tokushima-ken
Kagawa-ken
Ehime-ken
Kochi-ken
Fukuoka-ken
Saga-ken
Nagasaki-ken
Kumamoto-ken
Oita-ken
Miyazaki-ken
Kagoshima-ken
Okinawa-ken

実質5行で求められて便利。abbrevはたまにこういうことするのに便利で好き。

続きを読む

AWS CDKアプリを作る時のテンプレートリポジトリを作った

AWS CDKの昨今

最近は仕事でもプライベートでもAWSのリソース配備にはAWS CDKを使っている。
ちなみに最近はCDK for Terraformが出るなど、AWSに限らないツールキットを指向している雰囲気があるので「仕事は {ここにAWS以外のクラウドプロバイダが入る} だからな〜」「AWS以外も含めたハイブリッドクラウド環境だからな〜」という人も一度触ってみるとおもしろいのではないでしょうか。

ちなみにCDK for Terraformのようなものを作る布石はaws/constructsという前は@aws-cdk/core以下にあった階層や依存関係を表現する基礎的なクラス群が独立したライブラリとして提供されはじめたころからあったと思われる。

CDKはCloud Development Kitという名の通り従来のIaCというところから一歩進んだ「クラウド開発キット」であり、マネージドサービスを使っていくとインフラかアプリケーションかという区別が曖昧になっていくなら、構築支援するライブラリ・ツールキットもそれらを無理に分け隔てる必要はないのでは? という着想が垣間見える。実際使っていると隔たりが限りなく取り払われていく感触がある。
たとえばAWS CDKには手元のファイルをS3にアップロードしたり、手元のディレクトリでdocker buildしてECRにイメージをpushするライブラリなどがあったりする。Lambdaのコードを手元からアップロードするのはとても便利。

アプリケーションを上から下までプログラムで構築していくという考え方が徹底している。そういった話は1年前くらいの発表で触れていて、変わりない。

speakerdeck.com

CDKのベターデフォルト

cdk initで雛形はできるけれど、いくつかの点で不満がある。

  • ESLintが同梱されていない
    • ここに空白あったほうがいいですね、とか議論していい時代はもう終わった
  • renovateが設定されていない
    • CDKは頻繁に更新されるのでこれ無しではすぐに滅ぶ
    • アップデートはさほど苦しくないので自動化を徹底することが大事
  • GitHub Actionsの設定がない
  • TypeScriptのコンパイルが必須

などなど。

ESLintとかはともかく、TypeScriptのコンパイルを必須とするのは個人的にはCDKのような、Vanilla JSへ変換することが必須だったりアセットの整合性を追跡したいような要件がない場合には冗長だと感じる。
なので--noEmitとts-nodeで良いじゃん派。cdk deployとかして古いな〜 → コンパイルしていなかった、というようなできごとで失う時間のほうが多いと考える。

ので、良いかんじのtsconfigなどを込みにしたリポジトリを作った:

github.com

含めてあるものは上記の通りで、

  • ESLintと良いかんじの設定
  • renvoateの設定
  • 良いかんじのtsconfig

など。

テストなどはcdk initで出力されるものを基本的に踏襲している。

公開されたシンボルにJSDoc/TSDocを書くことをESLintでルール化したい

公開しているライブラリほどじゃないにせよ、チームで開発しているTypeScriptで書いたコードにちらほらドキュメンテーションしていきたい。

それESLintで

とりあえず今までろくに書いていなかった部分はいまさっき書き足すPull Requestを作ったけれど、今後手を入れる時にもちゃんと書いていってほしい。
で、こういうルールの徹底を人間がレビューで「ドキュメントおねがいします」って言うのは不毛。2020年代にやっていいことではない。

TypeScript/JavaScriptでやろうとなったらESLintでどうにかしたい。eslint-plugin-jsdocがJSDocに関連したルールを提供している。
JSDocはTSDocと基本的なフォーマットは同じで細かいタグのセマンティクスは差異がありそう。
そしてなんとeslint-plugin-jsdocはTypeScriptもサポートしている *1

ちなみにTypeScriptでドキュメント書く時はけっきょくどのフォーマットがええんや (なんかesdocっていうのもあったような) と思っていたらちょうど良いところに:
blog.pokutuna.com

最高。

ほどほどに始めたい

とはいえ社内でのみ開発されるアプリケーションのドキュメントをがちがちに書けというのも大仰なルールだし、そもそもTypeScriptで担えている型情報とかは書かなくて良いということにしたい。

前者は公開されたシンボルにだけドキュメントが書いてあれば良いということでよさそう。公開というのはexportされている、もしくは可視性がpublicであるフィールド・メソッドという定義にする。

eslint-plugin-jsdocにはそのものずばりpublicOnlyというオプションがrequire-jsdocルールにある。

そんなこんなで始めたESLintのルールが以下:

  "eslintConfig": {
    "extends": [
      "eslint:recommended",
      "plugin:@typescript-eslint/eslint-recommended",
      "plugin:@typescript-eslint/recommended",
      "plugin:@typescript-eslint/recommended-requiring-type-checking",
      "plugin:jsdoc/recommended"
    ],
    "plugins": [
      "@typescript-eslint",
      "jsdoc"
    ],
    "parser": "@typescript-eslint/parser",
    "env": {
      "node": true,
      "es6": true
    },
    "parserOptions": {
      "ecmaVersion": 2018,
      "sourceType": "module",
      "createDefaultProgram": true,
      "project": "./tsconfig.json"
    },
    "rules": {
      "jsdoc/require-jsdoc": [
        "error",
        {
          "publicOnly": true,
          "require": {
            "ArrowFunctionExpression": true,
            "ClassDeclaration": true,
            "MethodDefinition": true
          },
          "checkConstructors": false
        }
      ],
      "jsdoc/require-param-type": 0,
      "jsdoc/require-returns": 0
    }

むすび

*1:大半のルールにおいては。一部のルールはまだサポートされていない

react-type-safe-render: 第二引数にnullを許容しない安全なReactDOM.renderの型定義を書いた

@types/react-domで `ReactDOM.render` の第2引数 (container) はnullを許容しており、`document.getElementById` の返り値の型に合わせているそう。
しかしランタイムがnullを許容しているわけではなくnullを渡すと実行時例外になる。

TypeScriptを使っているのにこういうことが起きるのはなかなか悲しいので、nullを許容しないより安全なrender代替をexportするライブラリと、ReactDOM.renderを禁止するeslint pluginを作った。

GitHub - aereal/react-type-safe-render: Provides `safeRender` function that is more type-safe version of `ReactDOM.render` with no additional implementations

npm i -S @aereal/react-type-safe-render
yarn add @aereal/react-type-safe-render
npm i -D @aereal/eslint-plugin-react-type-safe-render
yarn add -D @aereal/eslint-plugin-react-type-safe-render

実装はとても素朴でRendererの定義から丁寧にnullを取り除いただけ。
関数の実体はReactDOM.renderそのものなので、実行時にペナルティは無い。

またESLintのプラグインを初めて作った。

@types/eslintにはプラグイン自体の型定義がなくてドキュメントを見ながら作っていたら、疲れていたのかしょっちゅうミスしてだいぶ時間がかかってしまった……。

最初はno-restricted-importsのruleを定義を持つconfigを配れば良いじゃんと思っていたのだけれども、利用者でno-restricted-importsを使いたい時に競合して上書きしあってしまうので実用的ではなく、似たような実装のruleを別に作ることにした。

けっこう楽しかったのでおもしろESLintプラグインを作って遊んでいきたい。

株式会社はてなを退職

2020年8月14日付けで退職する運びとなった。
入社が2012年なので勤続丸8年を迎え社内でも古株の方になってきつつある。Web業界にしてはわりと長くいたほうだと思う。
自分自身でもこんなに長く籍を置くとは思っていなかったので驚いている。

はてなに入社してから3039日

退職を決めた理由は主に2つ。

金沢移住

1つめは、現在住んでいる京都を離れて金沢で暮らしたいと考えたから。

数年前に観光で訪れた金沢を歩いてから一目惚れしてしまい、自分がここで生活する想像をするうちに単なる夢想から具体的に実現することを考えはじめた。
これを書いている時点で、株式会社はてなの事業拠点は東京と京都のみであり、在宅勤務は育児や介護、その他会社が認めるに足る理由があるケースのみ認められている。
平時は週数日程度スポットでの在宅勤務はマネージャーと合意した上では認められている。またコロナ禍においては在宅勤務推奨となっている。ただし、継続的にフルリモート勤務というのは上記の通り認められる事例は限定的になっている。
このまま在職しつづけても実現が難しそうと判断したのが、転職を決意した最大の動機といえる。

制度設計や判断について特に言うべきことはない。単に自分のニーズに合わなかったというだけのことだと思う。

幸か不幸かコロナ禍でリモートワークを半ば余儀なくされ当事者は拡大しているので、議論が進む機会となることを願っている。

一応、制度の拡大について提案してみたが諦めた。
世の事例を調べるに、ローカルワーク *1 に慣れたそれなりに成熟している企業がリモートワークに切り替える際には、

  • トップダウン
  • 合理性や生産性の観点で評価するというより、働きやすさ・自己実現の促進という観点を優先させた

事例がほとんどだった。

つまり、トップがある物差しを差し置いて別の物差しを守ろうとする強い判断を起こしたというヒロイックな事例しか見つからなかった。
「働きやすさを守る経営者」というと美しく見えるが一長一短であると思うし、どちらが良いという話でもない。

ここで重視したのは、生産性がローカルとリモートでどれくらい変化しうるとか、それをどう埋め合わせるための仮説や検証をこうしたとか、経営判断に繋がる十分な強度を持った提案の根拠として十分な仮説や先行事例を当時は見つけることができなかったということ。

ただしこれらは転職活動を始めた当時の調べによるものであって、現在は状況が変わっているのでこれまで在宅勤務の導入に踏み切っていなかった企業がうまくバランスさせながら導入を試みる事例や方法論がより多く世に出ていくことと思う。

そして、当社は企業全体の生産性と働きやすさをバランスさせる制度を前提としており、なかなか骨が折れそうなので諦めることにした。
実際、全体最適を考えてリモートワークを拡大しようとすると慎重にならざるをえないと自分も思う。しかし、今自分が選びたいのは組織全体にとって善となることより、個人の願望を十分なスピードで叶えることだった。

また、リモートワークが前提となった世界でではどううまくやっていくか? という問題に取り組みたいと考えた。
過去に失敗した事例はいくらでもあるし容易な道ではないことは承知しているが、それでもフロンティアに立ってどう解決するかに自分の時間と情熱を捧げたい。

後述するように、他の動機もあって留まることにこだわることはないと考えた。

ちなみに、在宅勤務ではなく通勤手当の拡大という線でも提案したがこちらも諦めた。在宅勤務の拡大より合理性の面でより望み薄 *2 だと考えていたので、これも仕方がないと思う。

スーパーリセット

2つめは、大きな変化を欲したから。

端的に言えば老害なりかけの自分を一旦捨てたかったから。

blog.kentarok.org

8年勤めて、様々なことに慣れた。仕事の進め方や手続きで不明なこともない。
中心に据えられている事業分野で求められるであろう技術・スキルはそれなりに備えていると思うし、業界が発展してもキャッチアップしつづける自信もある。
それなりに信頼も得ている。自分の発言はそれなりに尊重してもらえる。

でも、ふとした時に自分ってそんなに大した人間なのか? って思う瞬間が増えた。これって、単に時間を重ねただけの結果なんじゃないの?
ここに至るまでにもっと短い時間で済ませられたり、同じ時間をかけたらもっと遠いところに至れる可能性はなかったの?

ちゃんと自分は成長するべくして成長したのか。エンジンはへたっていないか、惰性に任せきりではなかったか、そういった自問自答に自信をもって答えられる根拠は少ない。
単に周りに恵まれただけで、自力は大しことがないのではないか。

自分は仕事以外にも時間を使いたい趣味はいろいろあるし、仕事一筋でも大好きというわけでもない。働かずに暮らせるなら今すぐそうしたいと思う。
しかしそれも難しいので、ならば生活の中で少なくない時間を使う仕事はとてもおもしろいものであってほしい。おもしろい仕事は難しい。難しい仕事を果たすためには技量と信頼がいる。
そういえば面接で当時社長だったjkondoさんに「僕は仕事がしたくないです。仕事を仕事だと思ってするつまらないことは絶対にしたくないです」って言ったおぼえがある。

株式会社はてなに留まってもそういう仕事ができる可能性は十分にあると思う。しかし自分がへたっていないか、ちゃんとおもしろい仕事を楽しみつづけるだけの体力が今もあるのか、それを維持できる体なのか、ということを試したい。
そのために、自分の身ひとつ以外は無いところに身を移してみたいと考えた。

8年ちょっとでやったこと

Resume - aereal

転職活動を始める際にさっと職務経歴書にまとめた。ここに書くことに苦労しないくらい色々とおもしろいことがやれたのは本当に良かった。
複数の相手にURLだけ伝えれば良い・見るであろうぎりぎりまで手直しできる、などのメリットがあるのでPDFとかを都度送るのは非合理だなと思った。

新サービス立ち上げから独自ドメインHTTPS配信、オンプレミスからクラウドへの移行などなど。Webのソフトウェアエンジニアとして一通りここは通りたいと思っていた分野を一巡りできたのではないかと思う。

特に独自ドメインHTTPS配信システムを作るのは良い経験になった。RFCで定められたプロトコルに従って実装を書いたり、そもそもTLSまで降りてプロトコルを学んだり、それまでのWebアプリケーションエンジニアから少し踏み出したエンジニアリングができた。

これから

そんなこんなで転職活動を始め活動を終了した。8月から新しい会社で働く。
金沢で暮らしたいという意思を伝えて理解いただいたうえでオファーをいただいたので確実に移住への大きな一歩を踏み出した。

次もWeb業界でソフトウェアエンジニアをやる。試用期間が終わるまでは所属は明らかにはしないと思う。クビになったらダサくて恥ずかしいので。

転職活動はかなり消耗したのでしばらくやりたくない。まず初めての転職だということもあるし、おまけにCOVID-19の拡大と重なってしまい現職の仕事も転職活動もだいぶ大変になった。
内定が出たGWごろは、楽しみだった旅行もライブもすべて無くなってしまい気分が完全に落ちていたので手放しで喜べなかったどころか、途端に不安になってしまったりかなり参っていた。

最後に。大学を中退したどこの馬の骨ともわからない人間が、10年近く経って贅沢に自己実現やキャリアのことを考えられているのも伸び伸びと仕事ができる環境があってのことだったと思う。
また、お世話になった方は数知れずいるものの、id:hitode909さんは自分が入社する以前からよく気にかけてくださり、大学もアルバイトも辞めて実家に帰るか野垂れ死ぬか考えていた時に「(はてなに) アルバイト応募してみませんか」と声をかけてもらえなければこうしていることはなかったでしょう。
入社してからもソフトウェアの話、仕事の話、おもしろ技術の話、様々に刺激を受けお世話になりました。数年来hitodeさんが務めたチームのリーダーを引き継ぐと決めた時にやっと同じ土俵に立てたように思い、とても感慨深くまたやっと自立できたと思える瞬間でした。
こういう話はしたことがなかった気がするけれど、ずっと意識していたのです。

在職中は他にも挙げきれないほどの方々にたいへんお世話になりました。本当にありがとうございます。引き続きインターネットでお会いしましょう。

*1:同一拠点で勤務すること。オフラインと表現することもあるが、リモートとより対称がとれていそうなのでこの表現を選ぶ。

*2:近距離通勤手当を福利厚生として支給している

JWEは毎回ランダムなInitialization Vectorを使用するので得られるトークンは毎回異なる

タイトルですべて言い切ってしまった。

JWE (= JSON Web Encryption) にはInitialization Vectorというフィールドが含まれており、これは暗号化処理ごとにランダムな値が使われる。
なので、同じペイロード・同じ秘密鍵を使って暗号化しても暗号化したトークンは異なる値になる。

もともとJWS (= JSON Web Signing) で署名したトークンを使っていて完全一致でテストしていたコードが暗号化するようになって必ず落ちるようになりハマって調べた。

複合して元のメッセージが得られれば良いので暗号化した文字列が毎回異なっていても良い、というのは暗号化において一般的なのかもしれないと後から思い至ったけれど、同じ入力・秘密鍵を与えて変わると思っておらず、テストの書き方がおかしいのだと思い込んで時間をつぶしてしまった……。

scrapbox.io

Scrapboxにもまとめた。

cloud.google.com/goのリクエストがX-Rayでトレースできないので土日を潰して調べて完全に理解した

cloud.google.com/goはGo向けのGCPAPIライブラリ。

一部を除き単にHTTPリクエストを送っているのでX-Rayでトレースする *1 のは造作もないだろうと思ったら思いがけず難航し、だらだら調査していたら2日かかってしまった。

詳しいメモと結論はScrapboxにまとめた。

scrapbox.io

読んだのは

の3つ。

VSCodeでdelveを使ってデバッグする体験がだいぶ良くて捗った。というかこれがなかったらつらくて諦めていたと思う。

土日を潰したけれど結果的によく使う大きなライブラリのコードリーディングをする良い機会になった。特にgolang.org/x/oauth2は雰囲気だけ知っていたけれど、まとまった時間をとって読んだりメモしたことはなかったので。

あと複数のライブラリを行き来しながらメモを書くのにScrapboxがかなり役に立った。
最初は調査用メモのページに実行パスをあれこれ書いていたけれど、階層が深くなっていくし同じメソッドを複数回呼ばれている時に表現しようがなくて困ったけれど、各関数ごとにページをわけたらすっきりする。
ページのリネームが簡単にできるので、書く時は `Cred()` とかにしておいて、後からパッケージ名を含めた完全修飾名にして検索しやすくするのも苦ではなかった。しかも後から補完が効いて便利だし。

早くにoauth2のissueを見つけて、てっきりこれがすべての原因だと思っていたけれどデバッガを使っているうちにトークン取得リクエストだけではなくAPI呼び出しキャプチャするaws-xray-sdk-goの実装が呼ばれないのは変だということに気がつくまでに時間がかかった。
これに気がついてからはあたりをつけて調べは早くに済んだけれど。

*1:github.com/aws/aws-xray-sdk-goを使って

GAEのapp.yamlに秘密の情報を含めたい時

app.yamlに公開したくない情報を含める - aereal-techより。

環境固有の値とかapp.yamlに書いてコミットしたくないけど、CD = Continuos Deliveryするためには必要でどうしよう、という時に思いついた策。

valid JSON is valid YAMLなので、雛形となるJSONリポジトリに置きjqで編集して秘密の情報を含めたJSONをapp.yamlとして出力する。
GitHub Actionsだとよくjqを使ってJSONをいじったりするけどYAMLだしなあ……と悩んでいた時にJSON is YAMLじゃんということに気がついた。

実際の例:

GCPだとSecrets Managerを使うのが筋なんだろうけれど、複数のシークレットを取得する方法がなくてシークレットの数だけAPI呼び出しが必要になる。
GAEでアプリ起動時に呼び出すのもばかばかしいし、個人の小規模なプロジェクトだからGAE用のビルドイメージを置いたGCSをうっかり覗かれて漏洩ということも考えにくいしまあいいかと思っている。

あと基本的にGitHub Actionsからのみデプロイするので秘密の情報の管理がGitHub Actionsのsecretsに集約されるので都合が良い。

AWS Systems Manager Parameters Storeは暗号化オプション付きでありながら複数の値を取得できて使い勝手が良いのでGCPにもこういうソリューションがほしい。

人間が関わりあう時間の価値を最大化するためのオートメーション

コードを書かない問題解決

ソフトウェアエンジニアとしての価値観とか仕草みたいなのはだいぶid:hitode909さんの影響を受けており、その中でも自分が大きく変わったと思うのは、問題解決の手段としてソフトウェアにこだわりすぎないという視点を手に入れたこと。

自分は本来的にはコードを書くのが大好き人間というかyak shaving大好き人間なので、コードを書きはじめて実現に至るまでのすべての寄り道を楽しいと思う性質だけど、一方、チームや組織という文脈でそれが常に正しくて価値が最大かというとそうではない。
……ということに気が付かされたのはひとでさんと仕事していて自分がソフトウェアを作るという方法にこだわって悩んでいると「とりあえずスプレッドシートで運用してみませんか」とか提案してもらえることがあり、最初はえーコード書きたいよと思っていたものの実際にやってみるとそれくらいで事足りる頻度の作業だったり、そもそも思っていたのと違うものを求められていたことがわかったり、と様々な示唆を得ることができた。

ひとでさんがなんでもかんでも手作業でやろうという考え方をしているかというとそうではなくて、酔っ払うといつもソフトウェア構築に関する良い話で盛り上がれる。
MVPを作る最短経路に対するアンテナが高く、かつその手法に拘泥しないというプロフェッショナル精神が高いのだと理解して、自分も心掛けるようになった。
自分はソフトウェアエンジニアであって、コーダーより広い職責を持つ人間なので、職責を果たすための手札は多いに越したことはない。

余談だけれども、ソフトウェア知識を得るためのメリハリをつけるために趣味ではおもしろさ・新しさに全振りするということを決めている。
そういった考え方をScrapboxの趣味プロダクトにまとめた。

オートメーション筋

それはそれとして、最近ソフトウェアで自動化するという手札をもっと研いでも良いのではと改めて実感しはじめた。
身の周りで人間が工夫して運用しているままのものがけっこういろいろあって、工夫しているだけあっていろんなパターンを実現できていて (できてしまっていて) これを後から自動化するのも大変そうだな……と思って見ている。

その時は人間がなんとかするのがMVPだと思っていたけれど、継続的に運用を改善したり見直す仕組みがないと大変なままなのでだったら最初からソフトウェアになっていたほうが柔軟性と引き換えに見通しが良くできたのでは、とかあれこれ考えたりした。
考えはじめたきっかけは在宅勤務が原則となったこともあるし、単にもっと前から人が増えてきたり、とかいろいろ。

そう物事は単純ではないけれどひとつ考えたこととして、最短経路というのは自分たちの手札によっても決まるのでそれを磨くというのも状況を改善する手段になるのでは、ということ。
徒歩で生活している人と車で生活している人にとって「近い」という感覚は異なると思う。

なので最近はTerraformとGitHub Appsを覚えようと思って実装しながら調べ物をしている。
ScrapboxのGitHub Appsを中心に認可方法について主にまとめている。App側がステートレスかつ安全に振る舞えるようよく設計されているな〜と感心している。

人間らしい暮らし

人間とコラボレーションする時には人間らしい時間が流れていると良いなと思う。
事務的・機械的なことを人間とやりとりしていると虚しい気持ちになってしまう。

在宅勤務・リモートワークが広がって人と人のリンクがオンラインになる (非同期、レイテンシが大きい、情報チャンネルが選択的に制限される) 中で、そういう虚しい時間だけが増えると他人と関わる時間が苦痛になりそうで嫌だなと思いはじめた。

コードレビューの話でも空白の話とかはlinterとかに任せて設計とかの話をしようという考え方があって、それもコラボレーションする時にその方法と相手じゃないとできないことに価値を持たせようということなのだと思っている。

自分は、人間同士が直接やりとりするのは常に最高でも好きでもなくて適材適所であるというスタンスに立っていて、だからこそ人間と関わる時間は実り多いものにしたい。

以上、引き継ぎとかをしたり、周りで人が増えてきて伝授する方法も変えなければ、という話題を見聞きして思ったことでした。

aereal.orgをNext.jsのSSGとContentfulに移行した

VPSCloud Bucketのホスティング機能→Firebase Hosting + Gatsbyという変遷を辿っていた自分のサイトをNext.jsのSSG (= Server-side generation) とHeadless CMSであるcontentfulに移行した。

aereal.org

最近出たNext.js 9.3でSSGサポートがちょっと良くなった:

These new methods have many advantages over the getInitialProps model as there is a clear distinction between what will become SSG vs SSR.

  • getStaticProps (Static Generation): Fetch data at build-time.
  • getStaticPaths (Static Generation): Specify dynamic routes to prerender based on data.
  • getServerSideProps (Server-Side Rendering): Fetch data on each request.
Blog - Next.js 9.3 | Next.js

かいつまむと、いままでgetInitialPropsという汎用的なAPIしか無かったのでこれを使うとNext.jsのstatic optimizationが効かなかったのだけれど、9.3で3つに分割されて最適化が効く範囲が広がった。

もうひとつ、Gatsbyを使うモチベーションとしてGraphQL + Apollo Toolingの組み合わせによるTypeScriptの型定義生成が便利で、GraphQLを直接サポートするHeadless CMSの類というとほぼGatsby一択だったという点がある。
元々contentfulは知っていてすこし触っていて好感触だったけれども、この型定義の生成がなくなるデメリットを受け入れられるほどではないなあと諦めていた。

しかしふと調べるとcontentful-typescript-codegenというツールがあってcontentfulのcontent modelから生成することができるようだった。実際、触ってちゃんと動くのでこれでよさそうとなり移行することにした。

あとついでに職務経歴書も書きはじめた。

作業メモ:

aereal.orgをGatsbyからNext.js + Contentfulに移行 - aereal-tech

趣味プロダクトのデザインドキュメントをScrapboxに書き始めた

scrapbox.io

仕事と趣味が曖昧な方の人間なのであれこれ触ったり作ったりするのが好きなんだけど、これまでは作ったものをGitHubに置いてREADMEを書いてそれだけで終わっていてなんかもったいなあと感じていた。

GitHubに置くからにはと、リポジトリをいきなり見に行っても情報が十分に凝集しているようにと書く一方で自分という文脈を踏まえた情報は意図的に書いてこなかったし、見栄を張ってREADMEを英語で書き続けているからどうしても微妙なニュアンスのテキストは書けずにいたりしたので、もうちょっとアウトプットの濃度を上げられないかとたまに考えていた。

最近、仕事でデザインドキュメントを書いていこうというムーブメントが社内で高まっていて、これはソフトウェアエンジニアのアウトプットとしてコード以外のかたちとして考えられる中でかなりおもしろい形式だと思って、他チームの書いたものを楽しく読んだりしている。
で、これを趣味プロダクトでやらない手はないなと思った。ので書き始めた。

Scrapboxに書いていくうちに、どんどんこれまで考えてきたことがかたちになっていて不思議な体験だった。

読んでほしいのは自分なりの趣味プロダクトの定義です。

scrapbox.io

ECS taskの停止理由をMackerelのグラフアノテーションとして記録する

github.com

記録するLambdaを作るAWS CDKのリソースライブラリを作った。

いますぐ npm i -S @aereal/cdk-ecs-task-retirement-events-mackerel-annotator !

f:id:aereal:20200204174634p:plain
こういうアノテーションが作られる

モチベーションと利点はScrapboxに書いたように:

[ECS]のtask停止は[Mackerel]にホストの退役と登録というかたちで通知されるが、その契機となった変化が何なのかがわからない。
[CloudWatch Events]を購読する[Lambda]が、コンテナの停止理由をMackerelのアノテーションとして付与する。
Mackerelのアノテーションはサービス (とロール) に紐付き、揮発していくコンテナより長いライフサイクルで残るため、連続的な変化を追いやすい。

cdk-ecs-task-retirement-events-mackerel-annotator - aereal-tech

……というところ。

どうぞご利用ください。

zsh: /usr/libexec/path_helperから逃れる方法 2020年版

macOSには /usr/libexec/path_helper というスクリプトがあり、これは /etc/zprofile で実行されOSがPATHをよしなに設定するというものだが、ユーザーが追加したパスより優先度高く追加するようになっており、かなり傍迷惑。
/usr/local/binなどより任意のパスを優先させたいのに〜〜〜ということがよくある。

Homebrewでzshを入れる際、過去には --disable-etcdir というオプションをconfigure時に渡すオプションとかがあったけどなくなっており、仕方なくforkして--disable-etcdirを付けたり、といろいろあったのだが、/etc/zprofileを読まないよう設定することもできて、これがおそらく最もポータブルな対処法でありそう。

unsetopt GLOBAL_RCSするだけ。

Commands are first read from /etc/zshenv; this cannot be overridden. Subsequent behaviour is modified by the RCS and GLOBAL_RCS options

zsh: 5 Files

注意したいのは /etc/zshenv は必ず読み込まれ、これはunsetopt GLOBAL_RCSでも回避できないこと。