近況

2021/5から会社員に戻りました。 仕事のオファーはなんだかんだ尽きないし、フリーランスは続けられそうでは有りまして、 しばらく会社員に戻るつもりはなかったものの、かくかくしかじかで会社員に戻りました。

どんな会社かと言うと、SOELUという会社で、オンラインのヨガを提供している会社です。 この会社はフリーランスとして関わっていたのですが、そこに晴れて正社員として関わることになりました。

決め手をあげると(生々しくないやつを除いて)、

  • 週4勤務でいいよってなった
    • 一見私にのっぴきならない事情がありそうですが、残りの1日で趣味とかやりたいという話をしました。
    • こういった事由でも少なくともきちんと検討はしてもらえる柔軟さがあります。
  • 採用活動にも少し関わっていて、続けざまにいい人材がとれた
  • 分野内では弊社はイニシアチブがある

などのギョーム的な良い流れがあったことに加えて、 社内にポーカーをやる人がいて、スプリント終わりにトナメが開催される、という点も良かったです。 私はポーカーが大好きなので、ギョームには関係ないですが、QoLがあがるため、この点も非常に魅力的でした。

仕事自体もビジネス的にもシステム的にもやることがたくさんあるので暇しなそうなところも良かったです。

そんなSOELUですが、正社員のネイティブアプリのエンジニアが不足していまして、たぶんネイティブアプリのエンジニアは特に歓迎されると思います。

転職を考えている方はノリで一回弊社に話を聞きに来ても良いかもしれません。

そういうわけで、とりあえず元気にやっています。

正社員になったので、小規模企業共済をどうするかなど未だに悩んでいますが、 とりあえずはしばらくサラリーマンとしてやっていきつつ、宝くじでも買おうかなという所存です。

NixOSで各言語のパッケージをNix経由での管理にせずに開発環境を作る

NixOSでは共有ライブラリの管理方法が他のlinuxディストリビューションと違い、/nix/storeに置いてある。 よって、例えば無邪気にnpm installでいれたcliがnot found扱いとなる。 なのでベーシックなやりかたとしては、Nixを使って各言語のパッケージも管理するというのがあって、 patchELFでpatchをあててinterpreterとrpathをセットし直すという形でderivationを書いたり、あるいは、そういった形でNixのパッケージとして公開されている。

ただ、Nixで各言語のパッケージを管理したくない気持ちというのはまぁあって、普通にnpmで管理して、雑にnpm installして動く、みたいなのがいいとおもうこともあるはずだ。

今回はelectronをリポジトリローカルなモジュールとして管理したかったというシチュエーションだったので、この条件を満たすshell.nixをつくった。

{ pkgs ? import <nixpkgs> {} }:

with pkgs;

let
  sharedDeps = atomEnv.packages ++ [
    libdrm
    libxkbcommon
    mesa
  ];

in
  (buildFHSUserEnv {
    name = "electron-test-env";
    targetPkgs = pkgs: sharedDeps ++ [
      nodejs-12_x
    ];
  }).env

やっていることとしてはnodeの依存とelectronの実行に必要な共有ライブラリの依存が入った環境をbuildFHSUserEnvを使って用意している。

shell.nixを用意する場合、mkDerivationmkShellを使うと思うが、その場合は、共有ライブラリの検索のためのコード(LD_LIBRARY_PATHの設定、あるいは、rpathのパッチ)とELFのインタープリタのパッチのコードが必要になってしまう。

しかし、buildFHSUserEnvを使うと、FHSに準拠した形で環境を用意してくれるので、必要なライブラリを依存に入れるnixファイルを書くだけで済む。

こういったshell.nixをプロジェクトルートにでも置いて、nix-shellを呼び出すだけで、あとは各言語のパッケージ管理ライブラリのみでパッケージを管理できる。(このnix-shellで起動したshellの中なら、無邪気にnpm installしたcliも動く。今回の場合はelectronのcliが問題なく動く。

結果的にはほとんどDockerfileを書いているのに近い感覚で開発環境を作ることができる。

すげえ便利なので、NixOSユーザーはbuildFHSUserEnvを使ってみると良いでしょう。

なお、詳細はNixOSのマニュアルにあるので、使う前は要チェックです。

ULIDのPureScript実装作りました

背景

ULIDのPureScript実装がないのでそのうちつくろうという意思だけ持っていたものの、その後半年以上経過し、気づいたら他の人に先に作られてた。 しかし、それはnpm packageのulidに依存しており、こんなのまでnpm packageに依存するのは嫌なので、やっぱり自分でPureScriptで書くことにした。

ULIDとは

端的に言えばソートできるUUIDみたいなもんです。 ULIDには時刻を表す部分とランダムに生成される部分があるからです。 その性質上RDBで用いる時にフラグメントしないです。 詳しくはこちら

成果物

purescript-simple-ulid

このブログを書く時点ではpackage-setsにPR出している最中なので、package-setsに入ってないかもしれません。

補足

Monotonic ULIDはつくってません。

名指しでやれ

自分のアウトプットを人にチェックしてほしいとき、というのは誰にでもあるし、仕事をしていれば日常的に観測できる事象である。

私はプログラマをしているが、プログラマの場合であれば、例えば、本番のデータを修正するスクリプトを他人にチェックしてもらうとか、単純にPullRequestをレビューしてもらう等だ。

この時に、不特定多数に対してチェックを呼びかけるというケースを観測することがある。 例えば、slackでのやりとりであれば、@channel等の不特定多数にたいするメンションのみを用いたやりとり、Pull Requestであれば、複数の人間をレビュアーに設定する、等である。

こういった不特定多数にチェックを求める行為をする癖がある人がいたらすぐにやめたほうがいい。

理由は明確で、チェックしないで無視する、あるいは、適当にチェックしてレスを返すという流れを生む確率があがるし、実際みんな基本無視で、レスをしていてもめっちゃ適当、という事例を見ているからだ。

他の人が見てる、自分が返さなくていいという前提になってしまうので、無視しやすいし、無視しなかったとしても真剣さのないチェックになって適当にレスを返しやすい。

きちんとチェックをしてもらいたい意思があるなら、多数にお願いをすること自体はいいが、それだけでは絶対に駄目で、必ず生贄を一人だけ指名する必要がある。「あなたがメインのレビュアーです」「あなたがチェックしないなら先に進みません」ということが相手に伝わらないといけない。

チェックをお願いされた側は、直接指名は自分一人だけなので「ちゃんとしなきゃ」と考えやすくなる、少なくとも無視はされなくなる。

人にやってほしいチェックがあったら、必ず名指しで生贄を捧げろ。もちろん生贄はちゃんとチェックしてくれそうな人、できそうな人を選びましょう。

RecoilにインスパイアされてPureScript用仮想DOMつくった

追記

ここに記述した内容は既に古くなっています。 内部実装は既に書き直されていますし、Hooks likeなAPIも少しだけインターフェースが変更されています。 興味のある方は直接purescript-grainへ見に行ってください。

動機

Recoilが思ったより話題になっていたので、PureScriptだったらどういう表現ができるかなと思ってつくりたくなった。

そういうわけで、PureScriptにおける仮想DOM実装の3作目が爆誕してしまった。

結果

purescript-grain

こういう感じになった

型クラスのインスタンスにした型が各状態になり各状態キーにもなるという感じになった。 実はここの表現に関してはかなり迷って、最初は、シンボル(型レベル文字列)と状態の型をもち、キーの型から状態の型への関数従属性をもった型クラスのインスタンスにすることで表現しようと考えたが、PureScriptはOrphan instance禁止なため、シンボルはどんなシンボルでもシンボルというひとつの型、且つ、上記の関数従属性があるので、型クラスの宣言と別のモジュールでインスタンスの宣言をするとコンパイルが通らない。 よって、そこから少し右往左往してこの形に落ち着いた。

グローバルステート

以下のように任意の型をGlobalGrainインスタンスにし、状態の取得・購読や更新関数の取得をプロキシ経由で行う。

その型のコンストラクタ関数の参照を型の参照とみなし、状態のキーとして扱い、一意に識別する。

各所で勝手に宣言された状態は、ひとつのオブジェクトにおしこまれるようになっているため、全状態を見たりできるdev toolを作ろうと思えばつくれる状態にはなっている。

ただ、現状は型の参照をキーにして、uuid v4ベースの文字列を管理し、その文字列を内部で状態のキーとして使っているため、ヒューマンリーダブルではない。

これに対するアプローチは状態名のヒューマンリーダブルな表現を登録してもらうか、あるいは、型からモジュール名を含めたシンボル(型レベル文字列)をつくる、みたいな、コンパイラが解決する特殊な型クラスがあったりするといい。

後者の場合は、以下のtypeRefOfの実装もしなくて済むようになる。 後者の案に似たような提案はされているのでそういった機能が入ることを0.1%くらい期待しているが、あまり期待できない。

前者の案を採用する場合は、所詮表示用なのでユニークである制約はつける必要はないが、まぁだるいといえばだるいので、結局、現状はヒューマンリーダブルな名付けはしなくていいようになっている。この課題に関しては先延ばしにするということにした。

import Prelude

import Grain (class GlobalGrain, GProxy(..), VNode, fromConstructor, useUpdater, useValue)
import Grain.Markup as H

newtype Count = Count Int

instance globalGrainCount :: GlobalGrain Count where
  initialState _ = pure $ Count 0
  typeRefOf _ = fromConstructor Count

view :: VNode
view = H.component do
  Count count <- useValue (GProxy :: _ Count)
  updateCount <- useUpdater (GProxy :: _ Count)
  let increment = updateCount (\(Count c) -> Count $ c + 1)
  pure $ H.div
    # H.onClick (const increment)
    # H.kids [ H.text $ show count ]

動的なアイテムに対するグローバルステート

なにか動的なアイテムにそれぞれに対して、状態をつくりたい、要するにUIへの通知範囲を極端にしぼりたいケースにも対応している。

以下は簡単な例である。 この場合は、プロキシの値がもつキーと型への参照を用いてアイテムごとの状態キーが作られるようになっている。

import Prelude

import Grain (class KeyedGlobalGrain, KGProxy(..), VNode, fromConstructor, useUpdater, useValue)
import Grain.Markup as H

newtype Item = Item
  { name :: String
  , clicked :: Boolean
  }

instance keyedGlobalGrainItem :: KeyedGlobalGrain Item where
  initialState (KGProxy key) = pure $ Item
    { name: "Item " <> key
    , clicked: false
    }
  typeRefOf _ = fromConstructor Item

view :: String -> VNode
view key = H.component do
  Item item <- useValue (KGProxy key :: _ Item)
  updateItem <- useUpdater (KGProxy key :: _ Item)
  let onClick = updateItem (\(Item i) -> Item $ i { clicked = true })
  pure $ H.div
    # H.onClick (const onClick)
    # H.kids [ H.text $ item.name <> if item.clicked then " clicked" else "" ]

その他

この記事の本筋とは関係ないので書かないが、ローカルステートもある。 また、FFIでnpmパッケージを使っておらず全体的にPureScriptで書いてある。

また、2作目につくった仮想DOMは、でかいひとつのグローバルステートしかもてない制約と一部グローバルステートしか持てないことで不便になるケースに対応するための仕組みをいれた形のものだが、多数のファイルが型レベルでグローバルステートに依存する設計になっており、ステートに手を加えると、大量のファイルが再コンパイルされるので、 コードベースがでかくなってくると差分ビルドしてても重い。 というかそういう状況が発生し始めていた。

3作目のpurescript-grainは各グローバルステートの宣言をモジュールに分けておくだけで、仕組み上同じ問題は起こらない。

また、仕組み上、本家のReact hooksと違い、呼び出し順序が変わろうが、呼び出したり呼び出さなかったりしようが、バグらない。

既に少し派生パッケージをつくってみたが、書き心地としては悪くない。(自分が作ったので自分がそう思うのは当たり前だが...

なお、package-setsに追加したものの、まだpackage-setsがリリースされてないし、今日もさらにアップデートしたので、 試したくなった場合は、packages.dhallのadditionに手動で加えてもらう必要が有ります

新年が始まったわけだが

2019年

まぁホントに色々やったんだけど、ギョームとしては、WebRTC沼に参戦したこととPureScript及び俺製VirtualDOMのpurescript-freedomをぶちこんだこととか 、AWSからGCPのインフラ移行やったのとかログ基盤作ったりあたりがトピックかな。 今年はわりと大げさめなタスク多かったかも。 WebRTC一本で飯食える人がいる意味がよくわかった。商用SFUさまさまです。

プライベートは二人の子供に振り回されててんやわんやしてた。一日のうちに何に体力を使うかの配分について改善のしようがある。

家を買おうとして9000万の家でも買えるとファイナンシャルプランナーに言われたが、自分で正確なライフプラン表つくったら絶対に買えないレベルだったのでファイナンシャルプランナーの言うことを鵜呑みにしてはいけない、というかあいつらもただソフトに適当に数字打ち込んで御託並べてるだけなので信用してはいけない。

2020年

今年は自分のサービスで少しでも売上を立てる年にする。 歳をとって待つのが得意になったので長い目で見ながらやっていく。

家は買いたいけど新築はやっぱり無駄に高い。中古を狙っている。 家持ってる人で家売りたい人は、twitterの@oreshinyaまで連絡ください。買いたいエリアだったら検討します。

PureScriptのJWT用のライブラリを作りました

PureScriptのJWT用ライブラリ、purescript-simple-jwtを作りました。

一応既存のものでpurescript-jwtというライブラリがありましたが、デコード専用、且つ、署名の検証もしないものだったので、自分で作ることにしました。

使い方

エンコード

encode :: forall payload. WriteForeign payload => Secret -> Algorithm -> payload -> Effect Jwt

シークレットとアルゴリズムペイロードを渡します。 アルゴリズムついては、HS256とHS512に対応しています。 ペイロードについては、仕様上不定なので、まぁ適当にレコード渡してください。

デコード

decode :: forall payload. ReadForeign payload => Secret -> Jwt -> Effect (Either JwtError payload)

シークレットとJWTを渡します。検証時に用いるアルゴリズムはJWTのヘッダから勝手に選びます。 トークンがおかしかったり、検証に失敗したりするとエラーが返ってきます。 ペイロードの中身を使ったチェック(例えば、exp等による有効期限チェック)については、このライブラリの責務の範囲外としています。