cmake-js があれば node-gyp に依存せず NodeJS native addon を作れそう

github.com

cmake-js という cmake のラッパーを使うと、 node-gyp を使わずに NodeJS native addon を作れるみたいです。 node-gyp は Python 2.x に依存しているのが嫌なので、 node-gyp 依存をなくせるというだけで個人的にはけっこう嬉しかったりします。

ついでに NodeJS native addon の新しい C++ API であるところの N-API もちょっと試してみました (src/hello.cc)。これは、 NodeJS のJSエンジンである V8 API を抽象化して、V8 API のバージョンごとの差異を吸収する API layer です。N-API 登場以前の NodeJS native addon は NodeJS / V8 のアップデートですぐビルドできなくなっていたものですが、 N-API を使うようにすることで複数の NodeJS バージョンに対応することが容易になりそうです。

cmake-js + N-API で NodeJS native addon がかなり開発しやすくなりましたね。NodeJS はスクリプト言語としては十分に高速なので速度のために native addon を開発する必要はほとんどないのですが、既存の資産 の活用はもっと気軽にできていいので、native addon を開発しやすくなるのはありがたいです。

プロジェクト固有のルールを指定できるLinterであるところのQuerlyがめちゃ便利

https://github.com/soutaro/querly

  • Rubyを構文解析したASTに対して独自DSLでパターンマッチ&メッセージを出すツール
  • プロジェクト固有の事情に配慮したLinterとして使える
  • false positive 上等で注意喚起として使う

たとえばKibelaの querly.yaml から一部抜粋するとこんな感じです。

rules:
  # ...
  - id: kibela.order_by_string
    pattern:
      - "order(:dstr:)"
      - "where(:dstr:)"
      - "find(:dstr:)"
      - "exists?(:dstr:)"
    message: "文字列によるSQL構築は本当に必要ですか? SQL Injection を引き起こさないように気をつけてください。"
  - id: kibela.block_call
    pattern:
      - "yield"
    message: "yieldではなくblock.callを使いましょう。そのほうが渡す引数が明確になります。"

kibela.order_by_string のルールの :dstr: は double-quoted string で、変数展開を伴う生SQLに対して注意を促しています。実際Querlyを使い始めてから1年以上たちますが、「気をつけてください」というレベルのメッセージでも十分役に立ちます。プロジェクト固有のガイドラインを(DSLがサポートしているかぎり)どんどん足していけるのは非常にいいですね。

ルールの設定は querly console でREPLを起動できるので、そこで行います。Railsプロジェクトだと querly console app lib ですかね。対象がRubyなのでそんなに正確ではないものの、構文解析をするぶん正規表現によるパターンマッチよりも遥かに正確ですし、実用上はそれで十分です。

惜しむらくはRubyしかターゲットにできないこと! TypeScript 用にもほしい…(切実)。

なお実行にそこそこ時間がかかってpush前にやるのは大変なので、 Kibelaの場合はSider で実行を自動化しています。

See Also

「GraphQL APIだとバージョニングが不要」という言明は誤解を招くので避けるべき

1行で

  • 「特定の場合でバージョニングしなくても対応できることはある」程度なので、「バージョニング不要」とは言わないほうがよい

どういうことか

  • RESTful API から GraphQL へ、GraphQL から別の Web API systemへ、ということを考えると大きな意味でのバージョニングは必要
    • e.g. 実際にGitHub は GraphQL API を "API v4" と呼んでいる
  • 細かなレベルのバージョニング、たとえば1画面の仕様が微妙に変わるたびに /foo, /foo_201807_1, foo_201807_2 みたいにどんどん特定画面専用APIを定義していく、みたいな意味でのバージョニングは不要
  • fieldの追加は無造作に行ってよい
    • RESTful APIでもfieldの追加は普通はできる、ただし負荷に注意
    • 重いcomputed fieldの場合でも、GraphQLのほうは無造作に追加できる
  • fieldのrename, deleteはGraphQLでも気軽には行えない
    • @deprecated directiveはあるが、何かを保証するものではないので削除の際は利用者との間でコンセンサスをとる

DX: Developer Experience (開発体験)は重要だ

  • DX: Developer Experience (開発体験)とは、あるシステムを「気持ちよく開発・保守できるかどうか」を示すもの
  • 開発者は開発・保守という行為を通じたそのシステムのユーザーであり、DXはUXの一種である
  • DXがよいと日々の開発を楽しめるようになり、気持ちに余裕ができる
    • 気持ちの余裕がでるとコードの品質があがり保守時のデグレも減らせる
    • また、DXがよい事自体がDXを高める動機になり、正のスパイラルを見込める
      • つまり、「定められたタスク」(=義務)以上のことを行うようになる
  • DXが悪いと開発を楽しめず、「定められたタスク」以外のことをしたくなくなる
  • DXは放置すると悪化するので、「DXがよくも悪くもない」プロダクトは時間が経つに連れ「DXが悪い」になる
    • なので積極的にDXを良くしていく活動を奨励していくのがよい

いくつか興味深いフィードバックがあったので記しておきます。

⇢ PX: Programming Experience という概念を提唱している研究会があるようですね(DXとはかなり異なる概念のようですが): SIGPX: Special Interest Group on Programming Experience

TypeScriptの `ReadonlyArray<T>` を使いやすくするためにtslintを活用する

最近、Kibelaのtslint configの Rule: array-type を "generics" にしました:

+     "array-type": [
+       true,
+       "generic"
+     ],

以前は特に指定しておらず、 T[]Array<T> が混在してていて、それでよしとしていました。今でも、混在することによるデメリットは特にないと思っていいます。ただ、 Array<T> には一つだけメリットがあったのでこちらに統一することにしました。 autofixできるので、エディタ上では T[] と書いて保存時にtslintに Array<T> に直させるということができるため、導入のデメリットがないというのも大きいです。

さて Array<T> のメリットは、 ReadonlyArray<T> に直しやすいということです。 ReadonlyArray<T>Array<T> から破壊的変更を伴うメソッド(mutation methods)を取り除いたインターフェイスで、特にReactではstateやpropsに破壊的変更を与えてはいけないということになっているので、積極的に使うメリットがあります。

ReadonlyArray<T> についてTypeScriptの公式マニュアルではほとんど触れられていませんが、インターフェイスの章にすこしだけ記述がありますね。

https://www.typescriptlang.org/docs/handbook/interfaces.html

TypeScript comes with a ReadonlyArray<T> type that is the same as Array<T> with all mutating methods removed, so you can make sure you don’t change your arrays after creation:

let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!

なお同様に ReadonlyMap<K, V>ReadonlySet<T> もあるようです。

graphql-rubyの知見をscrapboxにまとめはじめた

scrapbox.io

React DOM elementsに focused プロパティがほしくなったとき

<input ref={(element) => this.input = element}/> しておいて this.input.focus() とか this.input.blur() とか呼び出すのはReact的ではないのでなんとかしたいものだなあ、と思って一旦こういう関数を作って運用してみることにしました。

// in TypeScript

// This function emulates "focus" attributes for React DOM elements
export function createFocusHandler<E extends HTMLElement>(focused: boolean) {
  return (element: E | null) => {
    if (element && element.matches(":focus") !== focused) {
      if (focused) {
        element.focus();
      } else {
        element.blur();
      }
    }
  };
}

これを次のように ref へのイベントハンドラとして渡せばOKです。

<input ref={createFocusHandler(focused)}/>

ラッパー component を作ってやっていくほうがいいような気もしますが、まあ動くのでとりあえずこれで。

yarn-deduplicate(1) で yarn.lock の重複エントリを最適化する

追記(2019/03/18): yarn-toolsからyarn-deduplicateが独立して使いやすくなり、 --strategy でdedupeの方法を選べるようになっています。タイトルも変更しました。

yarnpkg(1) を使って依存関係を管理しているとき、 yarnpkg upgrade-interactive は対話的にライブラリのアップデートができるので大変便利です。しかし、これを実行すると yarn.lock に不必要に重複エントリが作られることがよくあります。

nodejsで実行するケースでは重複があっても問題がないことが多いのですが、 クライアントサイドでは重複があると単純にファイルサイズが大きくなり。また、@types/* や react, jquery といったフレームワークはどの環境でも動作に問題が出たりするので、重複エントリは問題です*1。そこで今までは、 yarnpkg upgrade-interactive 後に 差分を眺めて重複エントリを1つにまとめるというタスクを手動でやっていました。

とはいえこの yarn.lock 最適化ロジックは機械的にできるはずなので、いいツールはないかと探していて、なければ作るのでもいいかと思っていいたところ、 yarn-deduplicate(1) というツールがその機能を提供しているようでした。

github.com

手元のかなり大きな yarn.lock でもちゃんと動いたので、 package.json の scripts セクションに次のようなdedupe scriptを登録して、 npm run dedupe で運用していこうと思います。

npx yarn-deduplicate --strategy=fewer && yarn install --force

こういうとき、 npx(1) を使うとプロジェクトの依存関係をいじらなくて済むのでいいですね。

*1:特にTypeScriptの型定義はグローバルスコープだったりするので、微妙に異なるバージョンの .d.ts が node_modules 以下に復数存在すると TS2300: Duplicate identifier が起きがちです。

nodejsをリビルドすることなくIntl APIをfull-icu相当のデータで使う

追記(2019/08/23): https://github.com/nodejs/node/issues/19214 によると、将来的にはfull-icuビルドがデフォルトになりそうです。


gfx.hatenablog.com

上記エントリの続きです。

その後調べた結果、 full-icu というNPM moduleでfull-icu相当のデータをインストールできることがわかりました。

https://github.com/unicode-org/full-icu-npm

中身については精査していませんが、 unicode-org が提供しているものなのでそれなりに信頼できるでしょう。

このモジュールをインストールすると node-icu-data-path(1) が提供されるので、それで得たパスを NODE_ICU_DATA 環境変数にいれるとnodejsの Intl APIで日本語を含めた多くのロケールデータを利用できるようになります。

HTC U11 は安心して人におすすめできるシムフリーAndroid端末だ!

www.htc.com

発売日に買って2週間ほど使ってますが、非常に快適です。

ここ1年で Android Z4 ⇢ Huawei P9 Lite ⇢ HTC U11 と変えてきましたが、一番ストレスフリーかもしれないです。シムフリーだし*1、変なビルトインアプリはあまり入ってないし*2、指紋認証がついてるし*3、Felica もついているし*4、USB debugも有効にできます*5。今のところ気になるのは、ボトムナビゲーションのホームボタンが指紋認証デバイスとかぶせているせいで独自実装なのがちょっと慣れないと使いにくいのと、ボトムナビゲーションにあるはずのIME切り替えボタンが存在しないのが不便だということくらいです。

Felicaと指紋認証のついているシムフリーのハイエンドAndroid端末というのがなくて困っていたわけですが、HTC U11は今のところ申し分のない出来です。よかったよかった。

*1:Xperia Z4はいい端末だがシムフリー版を手に入れるのがちょっと難しい。

*2:Huaweiのビルトインアプリは出来が良くなくてトラブルが起きがち。

*3:Xperia Z4は指紋認証が付いていないのが普段使いする上で唯一の欠点だった。

*4:Xperia Z4 はFelica がついている。

*5:Huawei P9 LiteはUSB Debugを有効にできない。